使用gdi+绘制缩放位图的问题

使用gdi+绘制缩放位图的问题,会有一个像素的偏差,网上看到一篇解决方案,收藏之:

http://www.tecgraf.puc-rio.br/~scuri/gdiplus/drawimage_scale_problem.html

GDI+ DrawImage Scale Problem

Here is the source code and screen shot of the problem described in:

http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.gdi/2007-01/msg00122.html

Source code: drawimage_scale_problem.cpp

The green lines marks the end of the image, or the last pixel of the image.

The red rectangle is drawn using the same rectangle coordinates used in the DrawImage.

For each test, 3 rectangles are drawn, one with no zoom, one with InterpolationModeBilinear, and one withInterpolationModeNearestNeighbor.

1. The Problem

Notice that the first image with no zoom is correctly drawn.

The next two images do not fill the entire rectangle, and the resample is not equally balanced in the edges.

2. First Solution

Draw using a larger rectangle and clip the result.

It works... But I have to change the current clipping, and it becomes more complicated if I have another clipping region selected. Notice that the clipping rectangle must be reduced by 1 pixel to be 100% correct.

3. An Experiment

What happens if the source rectangle is larger than the image?

The image is resized down!!! So I found that this is a valid operation and it affects the final result.

4. Using the Experiment results for a Solution

Just using a smaller source rectangle by 1 pixel, the image is correctly resized*. So the DrawImage parameterssrcwidth andsrcheight are in fact srcright andsrcbottom, that in Windows convention are outsize the image.

*But only when the image is zoomed. Notice that in the image with no zoom, using the same strategy is incorrectly drawn.

5. Another Solution

Michael Phillips Jr suggested another solution very similar of my first solution, also using clipping to get rid of the background.

Here is the result, but the resampling is not equally balanced. Notice that the clipping rectangle must be reduced by 1 pixel to be 100% correct.

6. Conclusions

None of these effects are described in the GDI+ documentation.

In my point of view it was a bug of the resampling algorithm (*see the After Words Bellow).

7. After Words (The real thing)

When using PixelOffsetModeHalf to center the pixel at (+0.5, +0.5) in the code, I found also some interesting results. See the screenshots of the problem just adding the PixelOffsetMode.

The size and position are correct (ignore the red rectangle), resampling is also equally balanced, but GDI+ insist in include the background in the resampling when usingInterpolationModeBilinear.

Now I think I understond what's going on. It is a GDI+ design decision and not a bug. But the lack of good documentation makes me lose several hours just to understand what's going on. Also the decision to include the background in the resampling is something weird for me, and not acceptable for our applications. I guess I will have to live with my solution using -1 in thesrcwidth andsrcheight.

Update - 20/Oct/2008

Vlad Grachov sent me a solution for the inclusion of the background. If you set theWrapMode toWrapModeTileFlipXY the background is filled with the own image instead of the background. I checked and it worked. Thanks.

Here are the results:

Notice the top red line how it is filled with black instead of the white background. The solution code is:

ImageAttributes imAtt; 
imAtt.SetWrapMode(WrapModeTileFlipXY); 
graphics->SetInterpolationMode(InterpolationModeNearestNeighbor);
graphics->SetPixelOffsetMode(PixelOffsetModeHalf);
graphics->DrawImage(&image, zoomRect, 0, 0, image.GetWidth(), image.GetHeight(), UnitPixel, &imAtt);

But keep in mind that PixelOffsetModeHalf will affect the position of other primitives. It is a good idea to set PixelOffsetModeNone after drawing the image.


If you have any comments or other approaches to this problem please feel free to contact me.

Best Regards,
Antonio Scuri
scuri@tecgraf.puc-rio.br


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值