It seems that despite having the word "unscaled" in it's name, this method is in fact drawing the image to scale to the rectangle.
I believe the way it should work is that the image should be it's regular size and clip only if it should extend beyond the bounds of the rectangle, right? Instead, it seems to be stretching to the size of the rectangle bounds.
I wouldn't call it a bug, but the name of the method is rather misleading (or the msdn documentation is inadequate). "Unscaled" refers to the print size of the image, which means it takes into account the HorizontalResolution and VerticalResolution settings. These will typically vary according to the source of the image -- a graphics program or a digital camera -- and you can of course change them yourself. For many purposes, you don't need to bother about the resolution settings. In that case, just use DrawImage, which will use the system resolution for all images.
Back in .Net Framework 1, there were reports that the "unscaled" DrawImage variants were more efficient than plain DrawImage. The difference, if it existed, seems to have disappeared in later versions of the framework.
Just in case anyone is interested, I was able to accomplish the task by using the DrawImage with the double Rectangle signature. The first Rectangle is the location of the image, and the second Rectangle is the clipping area. It's important to note that on the second Rectangle, it's position starts from the X,Y of the first Rectangle. Took me a little while to figure that out.
From your description it sounds like you might be misinterpreting exactly what the code is doing, although since we don’t see your code, we have to do some guessing ourselves.
Using the drawimage with destination rectangle and source rectangle isn’t so much clipping as it is selecting what portion of the source image to draw to the destination rectangle. If the source and destination rectangles are the same size, then there won’t be any scaling of the portion of the image copied. But if the source rectangle is smaller, then the image will be expanded and if the source rectangle is larger, then the image will be shrunk.
Perhaps it won’t matter in your application, but using the dst,src rectangle version of drawimage is one of the slowest versions of drawimage. I would have to test, and it might depend on the size of the source drawing, but another option would be to setup a clipping rectangle, and offset where you draw the second image to accomplish the same result, which might fit your original conception, but since we don’t have an example of what the code looked like you were trying to use, I can’t say for sure.
I'll post a quick example that just allows dragging a rectangle around an image and see the area under the rectangle being drawn in another picturebox. You move the rectangle just by using the left mouse. Dragging on the rectangle with the Right mouse button will resize the source rectangle. You can see what the result of moving and resizing the source rectangle has on the destination rectangle. The 2010 solution is attached in a zip file, but since there is not too much code, I'll paste the code here. If you don't want to download, or have an older version of VB.net, you can just create a new project, add two pictureboxes, #1 should be fairly small, say 100x100 and #2 should hold a reasonable size image (say 800x600 or larger) to drag around on.
Code:
Public Class Form1
Dim srcRect, dstRect As Rectangle
Dim srcRectBrush As New SolidBrush(Color.FromArgb(32, Color.Black))
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
srcRect = PictureBox1.ClientRectangle 'initialized the source rectangle to match our destination so no scaling of the image occurs
dstRect = srcRect 'initialized the dstRect as well, but we won't be changing its size, it will always fill the destination picturebox
End Sub
Private Sub PictureBox2_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox2.MouseMove
Static lp As Point, cp As Point 'lp = the last mouseMove position, cp will be the current mouse position
If srcRect.Contains(lp) Then 'if the mouse is inside the source rectangle
cp = e.Location ' save the position in a short named variable for convenience
Dim dx As Integer = cp.X - lp.X ' Calculate the distance moved in X and Y
Dim dy As Integer = cp.Y - lp.Y ' since the last mouseMove event
If e.Button = Windows.Forms.MouseButtons.Left Then ' If the left button is down, we want to move the source rectangle
srcRect.X += dx ' Update the X position
srcRect.Y += dy ' Update the Y position
PictureBox2.Invalidate() ' Invalidate our source picturebox so it draws the rectangle in the new position
PictureBox1.Invalidate() ' Invalidate our destination picturbox so it updates its image from the new source position
ElseIf e.Button = Windows.Forms.MouseButtons.Right Then ' Else if the right button is down, we want to change the size of the source rectangle
Dim newWidth As Integer = srcRect.Width + dx ' Determine the new width
Dim newHeight As Integer = srcRect.Height + dy ' Determine the new height
Dim redraw As Boolean ' Declare a flag so we only redraw if we actually change something
If newWidth > 10 And newWidth < 500 Then ' If the new width is within our desired min/max size Then
srcRect.Width = newWidth ' Update the source rectangle width
redraw = True ' flag that we want to redraw the pictureboxes
End If ' End If
If newHeight > 10 And newHeight < 500 Then ' If the new height is within our desired min/max size Then
srcRect.Height = newHeight ' Update the source rectangle height
redraw = True ' flag that we want to redraw the pictureboxes
End If ' End If
If redraw Then ' If the redraw flag is true Then
PictureBox2.Invalidate() ' Redraw our pictureboxes
PictureBox1.Invalidate()
End If
End If
End If
lp = e.Location 'save the current position of the mouse for the next time
End Sub
Private Sub PictureBox2_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
e.Graphics.FillRectangle(srcRectBrush, srcRect)
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
e.Graphics.DrawImage(PictureBox2.Image, dstRect, srcRect, GraphicsUnit.Pixel)
End Sub
End Class
Actually, the method I mentioned is not shrinking or stretching the image. It is in fact clipping it. But I'll take a look at your code as well. Thanks!
Actually, the method I mentioned is not shrinking or stretching the image. It is in fact clipping it. But I'll take a look at your code as well. Thanks!
Yes, I mentioned that if the source and destination rectangles are the same size, then it is not shrinking or stretching the image. But, it is also not technically clipping, since clipping would imply your are copying more area from the source than your destination and the destination would be clipping the excess area, the region outside the destination rectangle.
But since the source and destination rectangles are the same size, there is no drawing being attempted outside the bounds of the destination rectangle, so no clipping. You are just copying a fixed size rectangle from somewhere in the source to the same size rectangle in the destination.
My point is, if you did try to copy a larger area by increasing the size of the source rectangle, it would not clip the larger area in the destination, showing only a portion of the source area. It would shrink the larger source area to fit the destination rectangle.
I guess you could consider what you've done as not clipping (which is done on the destination), but snipping (selection of an area of the source), selecting a portion of the source to copy to the destination.
Hi Passel, it's normal to refer to selecting part of an image for viewing, saving etc. as "clipping" in photography and graphics. I assume that is the sense in which softwareguy means it. The original confusion (post 1) was caused by the so-called DrawImageUnscaledAndClipped method, which is even worse than I first remembered. It clips the image when the given rectangle dimension is smaller than the original, but scales the image when the rectangle is larger. So it's doubly misleading! I would say that the method is best totally forgotten, since it doesn't do anything you can't do with DrawImage. The source rectangle argument of DrawImage does in effect clip the original image. But you are right that the destination rectangle has nothing to do with clipping
Even within vb.net, the word clipping is used in different senses. For example, child controls are said to be clipped by the bounds of a scrollable control such as a Panel. There is also the ClipRectangle property of the PaintEventArgs, which refers to a selected area of the control to be repainted. Perhaps the sense of clipping you have in mind is the Graphics Clip (Graphics.Clip property or SetClip method). That clips part of the Graphics coordinate space, which isn't quite the same as clipping an image or clipping the final render, because the Graphics coordinates can be transformed by scaling, rotation and translation.
But I think all the examples you've given agree with want I'm saying.
When you scroll the controls in a panel, they would be drawn outside the destination rectangle (the panel), but are clipped, even though the control was probably called to draw itself, it won't draw outside the bounds of the panel.
Likewise, the ClipRectangle property of the picturebox prevents drawing outside the ClipRectangle, so even if I'm filling the picturebox with a random color each time I get a Paint event, if you drag a window across that window you get a smear of different colors across the picturebox as the new random color filling the picturebox is restricted to only drawing within the ClipRectangle, all drawing outside that rectangle is clipped, i.e. not drawn.
I believe that is the true meaning of clipping in Graphics, which in the 70's and early 80's would have been defined in hardware through the use of a mask in clipping planes in graphics memory to protect areas of the graphic memory from being able to be modified by drawing commands. Using clipping to refer to the process of selecting a portion of something to transfer, like "clipping" coupons from a newspaper, I think is a loose cross contamination of that action into the genre of computer programming, which is technically incorrect, but like many other words in languages, may slip into accepted multiple meanings and thus become a more ambiguous term than it originally was.
My reference to clipping in photography and graphic programs wasn't correct: I meant cropping. Still, I think it's clear enough that is what the OP is doing. PictureBoxes do not have a ClipRectangle property. PaintEventArgs.ClipRectangle is read-only and rarely used. It is the union of areas of a Control invalidated by the OS and/or by calls to Invalidate(rectangle). For Invalidate() without an argument or Refresh it is identical to the ClientRectangle. BB