dcsimg
Results 1 to 32 of 32

Thread: How to crop a picture

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    How to crop a picture

    In a picturebox I have an irregular shape image with a lot of white space all around it, on the left, top, bottom, and right sides. I would like to reduce the over all size of the picturebox so that only a small amount of white shows especially on the bottom and right.

  2. #2
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,550

    Re: How to crop a picture

    You are posting several graphics-related questions and it would be helpful to see screenshots many times in these cases. As for this question, if the backcolor is not a color in the image, you can literally scan the image from top to bottom, right to left and calculate the bounding box around the irregular shape. The furthest left,top pixel that isn't background color is top,left bounding box, etc.

    However, since you are drawing the shapes in your usercontrols, shouldn't you already know the size? I am assuming the shapes don't come with all that added space?
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  3. #3
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    Your requirement to crop leaving some background edge showing can complicate things.

    If you want 10 pixels of padding all around but say the left edge only has 5 pixels of background then you don't want to try to trim with left = -5.

  4. #4
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    Here's a quick and dirty attempt. I have not examined the "carpentry" (arithmetic) closely enough to determine whether it is pixel-perfect but it appears to be close.

    Name:  sshot1.png
Views: 144
Size:  4.4 KB

    BEFORE


    Name:  sshot2.png
Views: 133
Size:  4.6 KB

    AFTER

    Code:
    Option Explicit
    
    Private Sub mnuCrop_Click()
        Const PICTUREBOX_BORDERPX As Long = 4 '2 on each edge.
        Const PADDING As Long = 12 'We will leave this much padding, or less if there isn't enough
                                   'in the original picture.
        Dim Picture As StdPicture
        Dim CroppedLeft As Long
        Dim CroppedTop As Long
        Dim CroppedWidth As Long
        Dim CroppedHeight As Long
        Dim PaddingLeft As Long
        Dim PaddingTop As Long
        Dim PaddingRight As Long
        Dim PaddingBottom As Long
    
        With Picture1
            Set Picture = .Picture
            With New AutoCrop
                .CropByBackColor Picture1.hDC, Picture, vbWhite
    
                'Ok, some ugly fudging to leave a bit of padding without exceeding the original
                'bounds of the picture:
                CroppedLeft = .Left
                CroppedTop = .Top
                CroppedWidth = .Width
                CroppedHeight = .Height
                If CroppedLeft >= PADDING Then
                    PaddingLeft = PADDING
                Else
                    PaddingLeft = CroppedLeft
                End If
                If CroppedTop >= PADDING Then
                    PaddingTop = PADDING
                Else
                    PaddingTop = CroppedTop
                End If
                If CroppedLeft + CroppedWidth + PADDING <= .OrigWidth Then
                    PaddingRight = PADDING
                Else
                    PaddingRight = .OrigWidth - (CroppedLeft + CroppedWidth)
                End If
                If CroppedTop + CroppedHeight + PADDING <= .OrigHeight Then
                    PaddingBottom = PADDING
                Else
                    PaddingBottom = .OrigHeight - (CroppedTop + CroppedHeight)
                End If
                CroppedLeft = CroppedLeft - PaddingLeft
                CroppedTop = CroppedTop - PaddingTop
                CroppedWidth = CroppedWidth + PaddingLeft + PaddingRight
                CroppedHeight = CroppedHeight + PaddingTop + PaddingBottom
                'Otherwise we could just use .Top, .Left, .Width, and .Height!
            End With
            Set .Picture = Nothing
            .AutoRedraw = True
            Cls
            .PaintPicture Picture, _
                          0, _
                          0, _
                          .ScaleX(CroppedWidth, vbPixels), _
                          .ScaleY(CroppedHeight, vbPixels), _
                          .ScaleX(CroppedLeft, vbPixels), _
                          .ScaleY(CroppedTop, vbPixels), _
                          .ScaleX(CroppedWidth, vbPixels), _
                          .ScaleY(CroppedHeight, vbPixels), _
                          vbSrcCopy
            .AutoRedraw = False
            .Width = .ScaleX(CroppedWidth + PICTUREBOX_BORDERPX, vbPixels)
            .Height = .ScaleY(CroppedHeight + PICTUREBOX_BORDERPX, vbPixels)
            'Could also re-center the PictureBox if necessary.
        End With
        mnuCrop.Enabled = False
    End Sub
    Attached Files Attached Files

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    I made use of GetDIBits() above, but oddly enough I was not able to get the bits in top-down order by passing a negative value for nNumScans (aka cScanLines) as documented. I only bring it up because top-down would allow slightly less confusing code.

    I suspect this is because my test image was sourced from a GIF file and retained the original GIF-compressed format. Anybody have a clue about this?
    Last edited by dilettante; Jun 22nd, 2019 at 07:36 AM.

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,550

    Re: How to crop a picture

    Anybody have a clue about this?
    Haven't downloaded your samples. But when I want to flip the image for GetDIBits, I set the bmiHeight member of the BitmapInfo structure to negative, not the cScanLines parameter of GetDIBits.

    I think negative cScanLines works, but the starting row needs to be tweaked also (maybe the height vs 0?), similar to VB's .Render method -- been quite awhile since I messed with it for that purpose.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Works great! I fiddled with the two constants PICTUREBOX_BORDERPX and PADDING to make the edge borders smaller. In your post #3 you said my requirement to crop leaving some background edge showing can complicate things. Why is that? After thinking about it for awhile I decided that it would be better if there were no edges showing all around but the amount that was left in your original was OK

  8. #8

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Had to add

    .Picture = .Image
    Last edited by Code Dummy; Jun 22nd, 2019 at 02:01 PM.

  9. #9
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    447

    Re: How to crop a picture

    If it's an image file, IrfanView-->Edit-->"Auto-crop Borders" removes all white space without padding. If you want some padding, left click and drag, which creates a box. You can drag the box borders to resize it, then click Edit-->Crop selection(Ctrl+Y).

  10. #10

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    I can't use anything like that as this has to be done in my program while it's running

  11. #11
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    Quote Originally Posted by LaVolpe View Post
    Haven't downloaded your samples. But when I want to flip the image for GetDIBits, I set the bmiHeight member of the BitmapInfo structure to negative, not the cScanLines parameter of GetDIBits.
    Of course! (slaps forehead).

    This is what I get for trying to rush something together on a tablet where I don't have the MSDN docs installed. Slow Internet access also discouraged me from looking online. I need to heed my own advice always to develop making use of the documentation rather than trusting memory and the API Viewer.

    Thanks.

  12. #12
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    Quote Originally Posted by Code Dummy View Post
    In your post #3 you said my requirement to crop leaving some background edge showing can complicate things. Why is that?
    Because you can use the metrics calculated by AutoCrop directly, and the calling code becomes just:

    Code:
    Option Explicit
    
    Private Sub mnuCrop_Click()
        Const PICTUREBOX_BORDERPX As Long = 4 '2 on each edge.
        Dim Picture As StdPicture
        Dim AutoCrop As AutoCrop
    
        With Picture1
            Set Picture = .Picture
            Set AutoCrop = New AutoCrop
            AutoCrop.CropByBackColor .hDC, Picture, vbWhite
            Set .Picture = Nothing
            .AutoRedraw = True
            Cls
            .PaintPicture Picture, _
                          0, _
                          0, _
                          .ScaleX(AutoCrop.Width, vbPixels), _
                          .ScaleY(AutoCrop.Height, vbPixels), _
                          .ScaleX(AutoCrop.Left, vbPixels), _
                          .ScaleY(AutoCrop.Top, vbPixels), _
                          .ScaleX(AutoCrop.Width, vbPixels), _
                          .ScaleY(AutoCrop.Height, vbPixels), _
                          vbSrcCopy
            .AutoRedraw = False
            .Width = .ScaleX(AutoCrop.Width + PICTUREBOX_BORDERPX, vbPixels)
            .Height = .ScaleY(AutoCrop.Height + PICTUREBOX_BORDERPX, vbPixels)
        End With
        mnuCrop.Enabled = False
    End Sub
    I incorporated the changes to use top-down DIBs as well, simplifying AutoCrop.cls a little.
    Attached Files Attached Files

  13. #13
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    Quote Originally Posted by Code Dummy View Post
    Had to add

    .Picture = .Image
    Not to just display it, but it sounds like you are doing this using the PictureBox as a temporary canvas, then extracting .Picture to use for something else. If so, why not just use Picture1.Image when you want the results?

    Hardly matters I guess, it's just extra overhead.

  14. #14

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Code:
    Private Sub mnuCrop_Click()
        Const PICTUREBOX_BORDERPX As Long = 4 '2 on each edge.
        Dim Picture As StdPicture
        Dim AutoCrop As AutoCrop
    
        With Picture1
            Set Picture = .Picture
            Set AutoCrop = New AutoCrop
            AutoCrop.CropByBackColor .hDC, Picture, vbWhite
            Set .Picture = Nothing
             '
             '
             '
    Run-Time error: '-2147188736'

    GetDIBits() error 0

  15. #15

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Quote Originally Posted by dilettante View Post
    Not to just display it, but it sounds like you are doing this using the PictureBox as a temporary canvas, then extracting .Picture to use for something else. If so, why not just use Picture1.Image when you want the results?

    Hardly matters I guess, it's just extra overhead.
    Not sure I can BitBlt the .Image property

  16. #16
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    That error &H80048000 is saying "succeeded, but copied 0 scan lines." I'm not sure how you got there. Passed an empty Picture?

  17. #17

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Quote Originally Posted by dilettante View Post
    That error &H80048000 is saying "succeeded, but copied 0 scan lines." I'm not sure how you got there. Passed an empty Picture?
    I used your program straight out of the zip file from your post #12

  18. #18
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    Well I unzipped it and tested that and it runs fine. Not sure what else to suggest.

  19. #19

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Would being on XP be a problem

    Your first example ran just fine

  20. #20
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    The only significant change was top-down vs. bottom-up DIBs. I'm not sure why WinXP would have any trouble with that.

    One thing that is "iffy" here is that GetDIBits() is not supposed to be used with an hBitmap that is selected into a DC. I was surprised that it actually worked at all, but maybe there was a change to make it work after the caveat was first published? If so, perhaps on WinXP you can get away with it except when requesting top-down instead of bottom-up? Works both ways on Windows 10 1809.

    The bitmap identified by the hbmp parameter must not be selected into a device context when the application calls this function.
    For all I know it may even be dependent on the video adapter driver and/or adapter hardware capabilities.

    You could always fall back and use the first version of AutoCap.cls instead. The differences are minor and the improvements made were small. The newer one only scans through a "blank" image once before giving up instead of scanning 4 times.

  21. #21
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,550

    Re: How to crop a picture

    @Code Dummy. In dilettante's class, inside the second If GetDIBits(...) call in the function CropByBackColor, try changing this:
    from: .biHeight to: -.biHeight
    or replace: .biHeight with: mOrigHeight

    I think the negative height is the problem.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  22. #22
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    There was another serious bug that was masked in testing by using white as the background color. Now I have incorporated the suggestion above as well as flipping the 0BGR "VB color" format (COLORREF) to 0RGB format (RGBQUAD) for edge-scanning.
    Attached Files Attached Files
    Last edited by dilettante; Jun 22nd, 2019 at 06:13 PM.

  23. #23
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    This should be the last version I post, for the benefit of future readers. It optimizes the process a little by making use of prior scans to narrow each subsequent scan a bit (four scans in all: inward from the left, then top, then right, and finally the bottom).
    Attached Files Attached Files

  24. #24
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,550

    Re: How to crop a picture

    @dilletante: I had to look at an old Trim/Crop function I used (based on alpha vs bkg color). I think our logic is very similar.

    In my routine... also used a 4-scan approach, pseudo code follows
    Code:
    Scan #1, find top
    For rows = 0 to nrRows -1
       For cols = 0 to nrCols - 1
           if hit then set top and also make left, right & bottom for now. exit loops
       Next
    Next
    if top not found, then image is transparent (in my case) or blank (in your case)
    
    Scan #2, find left, if not already 0, adjusting inner loop as we go
    For rows = top + 1 to nrRows - 1
        For cols = 0 to left - 1
            if hit then set left and if lower than current bottom, make bottom too. exit loop
        Next
        exit loops if left = 0
    Next
    
    Scan #3, find right, if not already max, adjusting inner loop as we go
    For rows = top to nrRows - 1
        For cols = right + 1 to nrCols - 1
            if hit then set right and if lower than current bottom, make bottom too. exit loop
        Next
        if cols = nrCols-1 then exit loops
    Next
    
    Scan #4, find bottom
    For rows = nrRows - 1 to bottom + 1 Step -1
        For cols = 0 to nrCols - 1
            if hit then set bottom & exit loops
        Next
    Next
    By adjusting the inner loops as we go, we potentially scan less and less pixels each scanline, barring worse case scenarios like a 1-pixel image or a 1-pixel wide vertical line.
    Last edited by LaVolpe; Jun 23rd, 2019 at 12:28 AM. Reason: added pseudo code
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  25. #25
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    There probably aren't too many ways to skin this cat unless there are calls accessing the video adapter hardware via GDI. I can't even keep straight which versions of Windows hardware-accelerate GDI operations any more, let alone which operations.

    GDI Hardware Acceleration suggests that support varies based on the drivers installed as well as the OS and the hardware itself.

  26. #26

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Why does Picture1 need to be Appearance = 3D and BorderStyle = Fixed Single. If I make it Flat and None it doesn't crop all the way - It's OK on left and top but there is a border on the right and bottom but if 3D and Fixed Single there is no space around the image

  27. #27
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,550

    Re: How to crop a picture

    Look at this in your sample code: Const PICTUREBOX_BORDERPX As Long = 4 '2 on each edge
    Change it to whatever you need. If you want it borderless, change the constant to zero
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  28. #28

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    I did that and removed the picturebox frame and it does work but try this: add a button and another picturebox on the Form. Make the new picturebox borderless and AutoResize = True and in the button event put Picture2.Picture = Picture1.Picture. When you click on the button Picture2 is sized the same as the original Picture1 and not the size of the cropped image but if you leave Picture1 as is and do not change the code then Picture2 will be resized to the size of the cropped image. I don't get it

  29. #29
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,550

    Re: How to crop a picture

    You may want to toggle the AutoResize property after you change the picture
    Picture2.AutoResize=False: Picture2.AutoResize=True
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  30. #30

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: How to crop a picture

    Doesn't do anything

    Code:
    Private Sub Command1_Click()
     Picture2.AutoSize = False
     Picture2.Picture = Picture1.Picture
     Picture2.AutoSize = True
    End Sub
    also this

    Code:
    Private Sub Command1_Click()
     Picture2.Picture = Picture1.Picture
     Picture2.AutoSize = False
     Picture2.AutoSize = True
    End Sub

  31. #31
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,550

    Re: How to crop a picture

    Well, what do you get when you Debug.Print the following? If no change in before/after, that explains it
    Code:
    Private Sub Command1_Click()
    Debug.Print "Before: "; Picture2.Picture.Width, Picture2.Picture.Height
     Picture2.AutoSize = False
     Picture2.Picture = Picture1.Picture
    Debug.Print "After "; Picture2.Picture.Width, Picture2.Picture.Height
     Picture2.AutoSize = True
    End Sub
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  32. #32
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,719

    Re: How to crop a picture

    You could accomplish what you ask by flipping a few things around such as changing the size of Picture1 before the PaintPicture call in the previous code.


    Here is a version that takes everything out of your hands and does it all for you. It no longer just finds the cropped area metrics but goes ahead and does the cropping as well.

    To follow the discussion above, this demo uses the new version and two PictureBox controls. It only uses Picture1 as a source to create a new, cropped StdPicture and then assigns that to Picture2.Picture which has AutoSize = True.

    Code:
    Option Explicit
    
    Private Sub mnuCroptopicture2_Click()
        With New AutoCrop
            Set Picture2.Picture = .CropByBackColor(Picture1.hDC, Picture1.Picture, vbCyan)
        End With
        mnuCroptopicture2.Enabled = False
    End Sub

    Name:  sshot1.png
Views: 71
Size:  1.8 KB Name:  sshot2.png
Views: 70
Size:  2.2 KB


    I don't think there are any GDI handle leaks in that but somebody should check it over for anything I missed.
    Attached Files Attached Files

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width