Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Cropping and resizing jpegs in vb6 1

Status
Not open for further replies.

tedsmith

Programmer
Nov 23, 2000
1,762
AU
Just returned from a fantastic 15,000km camper trailer trip of Central and West Australia outback I have 3 hrs HD video and 3000 jpegs taken by the wife to integrate into a "home video"
In order for the Adobe video editor to cope with so many HD stills, I have to pre crop each jpeg from 3x4 rectangular, 2816 x 2122 pixel to 16x9 widescreen and save as a 1900 x 1080 pixel jpeg.
I also need to resize or zoom in on some of the pictures to reframe or eliminate unwanted objects.

I normally use Photoshop to do this but it is extremely time consuming. All other apps I have seen require you to do a lot of keyboard entry and fiddling because they expect you to retain the same aspect ratio.

Sometimes it is quicker to use Paint but this requires calculating and entering the % reduction to get the required pixel size.

I would like to be able to simply select the jpeg to a wide screen frame, expand the pic inside the frame with the mouse and shift horizontally or vertically until I have it the best and save to the fixed 1900x1080 pixels with one click.

What would be the best way to make a vb6 app that I can crop and re-size jpgs and always save in a set pixel result without affecting the picture size?

I can simulate this easily manipulating an image box inside a smaller frame but how do I convert the visible result to a jpeg of fixed pixel resolution?

 
Ted,

Didn't we discuss something similar about a year ago ... hang on ... <fx: tappety, tappety> .. yes, here we are: thread222-1667755

The main point there was that resizing in VB is quite possible, but the built-in, commonly available control and API methods are relatively low fidelity - and you'll lose quality in comparison with a professional tool such as Photoshop

As for saving a given image as a jpg - I'm pretty sure we've covered that for you multiple times ...

So, can we confirm that the bit you are really asking about is: how do I convert the visible result to a jpeg of fixed pixel resolution?

And I'll just mutter WIA 2 in preparation ...

 
Yes, I felt the answers I got then pointed to solutions using other products or using methods of which I am not familiar or knowledgeable to use or were just as convoluted as using Photoshop.

I was hoping for a simple drag and click solution using vb6 even if the quality was not professional and hoped other ideas might surface.

Most of the still pictures are close ups of wildflowers or objects where high resolution is not so important and they start off twice the resolution of a movie frame anyway. They would only appear for a few seconds in the context of the movie of the same subject.

The problem with resizing multiple stills in all NLE editors becomes apparent when you also have multiple tracks, dissolves, sub titles and effects and mix them with video - there is a limit to the number of things you can do and still get a quick smooth preview even with a i7 8core processor.
 
>using other products or using methods of which I am not familiar or knowledgeable

As we've previously said, you don't have a lot of choice if you want to save jpegs (whether cropped and rescaled or not); none of the standard VB6 controls know how to save a jpeg

>a simple drag and click solution

I assumed from your

>I can simulate this easily manipulating an image box inside a smaller frame

that you'd already got this bit working. Which is why I was seeking clarification on where you really needed assistance.
 
Yes, I do need assistance if I did it the way I visualise.
I would put the picture to be cropped in a 3x4 image box with a width initially the same as the width of my screen(1900x1200). This would initially crop part of the top and bottom of the picture.
I would have this image box inside a fixed frame that is set to fixed 1900x1080.
I'd have the required control buttons underneath along the bottom of the screen.
I would want to move and resize the image box under the frame to get the desired cropping result, always maintaining the aspect ratio of the original picture.

1. I cant see how to extract only these visible pixels from the memory that contained the whole original picture
2. I can't visualise how to convert the above (now of a different pixel count to the original) to a bmp of fixed pixel count (1900x1080) and save it. In some cases this reduced picture could be greater or less than the end result but always saved as 1900x1080. It would be the same number of pixels being actually visible to the eye in the frame.
3. At this stage I presume the picture is a bitmap somewhere in memory. Then I guess I could save it as a bmp or to jpg using methods you have already explained although it could probably be better to have it a bmp as this may need less conversion by the NLE editor.
4. If I used the mouse, how do I get the coordinates of a mouse pointer that is over an image box that is being moved by the mouse (like it does in the IDE)? If I use the Imagebox mouse coordinates, as soon as I move the image box, these change making the box jump back to where it was. The mouse coordinates for the frame only respond when there is no image inside that part of the frame where the mouse is. (So far I've used H&VScrollbars instead)

Regarding quality, I find that stretching a bmp in an image box in vb6 gives no worse image quality to doing it in Photoshop. Pixels are still pixels after all. Fine diagonal lines are just as jagged in both when you change size in other than direct multiples of the pixel sizes.

If I need to correct a bad jpg color balance or sharpness, I can always do it in Photoshop as an exception anyway.
 
>gives no worse image quality to doing it in Photoshop

In Photoshop (heck, even in ancient versions of Paintshop Pro) you can apply various filters that try and maintain visual image quality whilst resizing images. It strikes me that perhaps you are not using Photoshop to its best effect if a simple VB6 stretch (via PaintPicture or leveraging an Image control) gives the same results ... pixels are not just pixels, after all.


>I cant see how to extract only these visible pixels from the memory that contained the whole original picture

Have a look at the PictureBox's PaintPicture method
 
Thanks I will look at that

A saved screenshot JPG of an Imagebox picture is actually sharper than a screenshot of the same picture shrunk in the Photoshop editor and is identical in appearance to the saved jpg in Photoshop.

I am interested to see how a saved jpg of an imagebox will compare when of if I can work out how to do it.

The only advantage with Photoshop is if you want to also correct a poor original or compensate for the natural loss of pixels when zooming in a lot on a wise shot. The disadvantage is it is very time consuming requiring a lot of manipulation to get the final result exactly 1900x1080 pixels.


 
Yes PaintPicture seems to do everything I need by varying coordinates with HScrollbars_Change -

Thanks

I didn't realise I could stretch in a Picturebox so easily this way.

All I need now is a two finger mouse control to adjust the size and position like in an iPad!

When you press a mouse button the mosemove is normally disabled.
If I could get them to work at the same time I could say hold down the left button to vary the size when I move it and the right to vary the position. Is there an API or something that could do that?
 
>requiring a lot of manipulation to get the final result exactly 1900x1080 pixels.

Er ... I'd simply use the crop tool with a width and height manually set to 1900*1080 px (set in the Options Bar). You can even save that as a tool preset so it can be reused over and over again. Nothing very hard about that ...

I'm afraid I still think you are not using Photoshop to its best affect. Ah well. And I'd point out that 2 jpegs of the very same image may well vary in quality, based on the amount of compression selected. jpeg is a (visually) lossy format (well, there is a somewhat rare variant, lossless jpeg, but it is little supported)

>Is there an API or something that could do that?

Indeed there is ... but I'm not near a VB6 machine currently, so can't knock together a quick example. I've probably demonstrated the technique in here before. Try searching for rubberband or marquee
 
Thanks
I'm not arguing that Photoshop can produce a better result in many cases but for practical purposes the same amount of shrinking and expanding gives the same result. In many cases the attempt to smooth over jagged edges makes the picture in Photoshop appear slightly blurry. Correcting this by sharpening makes the edges more granular.
You can easily see this when you magnify the resulting graphic file.

Also I really wanted to see if I could do it at least just a well in vb6!

The jpg compressions and expansions used would be different but are still better than the compression of the original movie AVCHD that the pictures are mixed in with. The original still pictures are twice the pixels of the 1900x1080 movie

Incidentally if I save the cropped pic as a bmp and use this to mix in with the original video, whether Photoshop can save a reduced pixel jpg better than vb6 saving the Picturebox and converting to jpg is not an issue.

 
>and save as a 1900 x 1080 pixel jpeg
>save the cropped pic as a bmp

Wish you'd make up your mind
 
>When you press a mouse button the mosemove is normally disabled

Er, well, no, at least not here. But I think what you are getting at again is the relative coordiantes. And that's where the API may come in useful. See

ClientToScreen

and

ScreenToClient
 
Oh, and here's a fairly simplistic rubberbanding example I knocked together based on some old code of mine in thread222-974292

Code:
[blue]Option Explicit

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Private Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
Private Declare Function CreateRectRgnIndirect Lib "gdi32" (lpRect As RECT) As Long
Private Declare Function InvertRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long) As Long
Private Const RGN_XOR = 3



Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Static DrawingMarquee As Boolean
    Static CurrentMarquee As RECT
    Static PreviousMarquee As RECT
    
    If Button = vbLeftButton Then
        If CurrentMarquee.Top = CurrentMarquee.Bottom And CurrentMarquee.Left = CurrentMarquee.Right Then
           CurrentMarquee.Left = X
           CurrentMarquee.Bottom = Y
        Else
           CurrentMarquee.Right = X
           CurrentMarquee.Top = Y
            'Stop
            FastWindowFrame Form1.hdc, PreviousMarquee
            FastWindowFrame Form1.hdc, CurrentMarquee
            PreviousMarquee = CurrentMarquee
        End If
        
    Else
        With CurrentMarquee
            .Top = 0
            .Bottom = 0
            .Left = 0
            .Right = 0
        End With
    End If
End Sub



' Draws frame of rectangle you pass for the given DC
Private Function FastWindowFrame(ByVal hdc As Long, lpRect As RECT, Optional ByVal FrameWidth As Long = 1) ' xWidth As Long, yWidth As Long) As Long
Dim InsideRect As RECT
Dim tmpVar As Long
Dim OuterRgn As Long
Dim InnerRgn As Long

InsideRect.Left = lpRect.Left + FrameWidth
InsideRect.Right = lpRect.Right - FrameWidth
InsideRect.Top = lpRect.Top + FrameWidth
InsideRect.Bottom = lpRect.Bottom - FrameWidth

OuterRgn = CreateRectRgnIndirect(lpRect)
InnerRgn = CreateRectRgnIndirect(InsideRect)

CombineRgn OuterRgn, OuterRgn, InnerRgn, RGN_XOR

InvertRgn hdc, OuterRgn

' Clean up
DeleteObject OuterRgn
DeleteObject InnerRgn ' Note that keeping the region might be useful if we intend to do anthing with the outlined area later

End Function[/blue]
 
>Wish you'd make up your mind

These are alternatives, not indecisions.
A typical BMP reduced to 1900x1080 ends up with a larger file size (5meg) as the original 3x4 shot (jpg 3me from the still camera . When outputed as jpg it is reduced to about 500k.
As I understand it, the movie editor has to "convert" the jpg alternative internally to a bitmap to mix it with the video, so it may be faster to preview and manipulate edits using bmps. I have yet to make some tests on this because the difference only becomes significant after you put many stills in the one video.
Either makes no difference to the final file size of the movie on Blue Ray.

Thanks for the rubberbanding - I will experiment.

On Painpicture, as I manipulate the position around the screen, unless I erase the previous pic every time I move it, the previous areas remain persistent. So I have to clear the screen. As the screen background has to be black, this gives a white flash every time I move the pic.
Is there any better way to clear a painted pic or quickly remove the previous paint when you paint again?
 
1.
Please ignore the comment about paintpicture.
I now load the pic into a picturebox, paint that box's picture to a 1900x1080 hidden picturebox then transfer it to a smaller image box for preview and it works perfectly smoothly with no flashes.
I use the cursor keys & page keys to move the picture around and +- to vary size on the second picturebox.
I have a few favourite size and position settings on command buttons and it works lightning fast - Better than dragging with a mouse.
I simply SavePicture the second picturebox.

2.
Please ignored the strange link it appeared from nowhere when I submitted the post.
On Firefox lately I am getting links on this and some other sites appearing on certain words that when I hover over I get a pop up telling me I am the 1000000 visitor or I have won an iPad (if I pay money first) etc, - but not on Intetnet explorer. Kaspersky virus detection and Adaware doesn't report anything strange. Any idea?
I know it's not a vb6 issue but it might be something to do with why this odd link appeared in this thread?

Example on this thread I see a link on the word "start" in the 4th post in this thread. It's details are
 
>the previous areas remain persistent

Investigate the use of the AutoRedraw property of the PictureBox

Alternatively just move a frame around when dragging, and only repaint when finished.
 
The test turned into another link
Please don't open that link - it might be malicious
Here it is in a code box hopefully not as a link -

[
Code:
[URL unfurl="true"]http://i.trkjmp.com/click?v=QVU6MjE0ODE6NjpzdGFydDo1NmRlN2ZlNWNkNDUxNmVkMWM0MDdiMTgxOTZiZmJjODp6LTEzMTAtNzc4OTA6d3d3LnRlay10aXBzLmNvbToxMjU3Mjo0OGM1NjViNDM3MTE4ZjlkMGI2MjlkMTNjZmUyMjk1NQ[/URL]
code-]
 
I had a quiet moment, so here's an example that leverages built-in VB capabilies wherever it can to achieve something similar to what you describe but with a fairly minimal amount of code. It zooms, it scrolls (codelessly), it clips to a specified clip size, it saves ...

You'll need an MDI form
Then another form, Form1, set as an MDI child.
Add 1 picturebox, call it SourcePic
Add another Picturebox, call it DisplayPic
Add final picturebox as a child of DisplayPic, call it ClipPic. And set its Appearance to 0 - Flat

Then try the following example code:

Code:
[blue]Option Explicit

Public Xoffset As Long
Public YOffset As Long
Public PicScale As Long

Private Sub ClipPic_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        ClipPic.Visible = False
        Xoffset = X
        YOffset = Y
        ClipPic.Drag vbBeginDrag
    ElseIf Button = vbRightButton Then
        [green]'Here we can simply save ClipPic.Image as it contains the clipped picture we want[/green]
        SavePicture ClipPic.Image, "c:\temp\ted.bmp"
    End If
End Sub
    
Private Sub DisplayPic_DragDrop(Source As Control, X As Single, Y As Single)
    ClipPic.Move X - Xoffset, Y - YOffset
    PaintPic
End Sub

Public Sub PaintPic()
    ClipPic.Visible = False ' Helps remove any flicker
    With ClipPic
        .PaintPicture DisplayPic.Picture, 0, 0, .ScaleWidth, .ScaleHeight, .Left + 1, .Top + 1, .ScaleWidth, .ScaleHeight [green]' the  + 1 is to cater for the fact that control has 1 pixel border[/green]
    End With
    ClipPic.Visible = True
End Sub

Public Sub ScaleDisplayPic(PicScale As Long)
    MDIForm1.Caption = "PiccyThing. Zoom level: " & PicScale
    
    Form1.Width = ScaleX(SourcePic.Width * (PicScale / 100), vbPixels, vbTwips)
    Form1.Height = ScaleY(SourcePic.Height * (PicScale / 100), vbPixels, vbTwips)
  
    With DisplayPic
        .Width = SourcePic.ScaleWidth * (PicScale / 100)
        .Height = SourcePic.ScaleHeight * (PicScale / 100)
        .PaintPicture SourcePic.Picture, 0, 0, SourcePic.ScaleWidth * (PicScale / 100), SourcePic.ScaleHeight * (PicScale / 100), 0, 0 ',  .ScaleWidth, .ScaleHeight
    End With
    Set DisplayPic.Picture = DisplayPic.Image
    PaintPic
End Sub

Private Sub DisplayPic_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        ClipPic.Visible = False
        ClipPic.Move X, Y
        PaintPic
    End If
End Sub

Private Sub Form_KeyPress(KeyAscii As Integer)
    Select Case KeyAscii
        Case Asc("+")
            PicScale = PicScale + 5
        Case Asc("-")
            PicScale = PicScale - 5
        Case Else
    End Select
    ScaleDisplayPic PicScale
End Sub

Private Sub Form_Load()
    SourcePic.AutoSize = True
    SourcePic = LoadPicture("c:\tv.jpg") [green]' Choose your own source ...[/green]
    
    ' In reality these 10 would  be set at design time
    Form1.ScaleMode = vbPixels
    SourcePic.ScaleMode = vbPixels
    ClipPic.ScaleMode = vbPixels
    DisplayPic.ScaleMode = vbPixels
    DisplayPic.BorderStyle = 0
    DisplayPic.Top = 0
    DisplayPic.Left = 0
    DisplayPic.AutoRedraw = True
    ClipPic.AutoRedraw = True
    ClipPic.BorderStyle = vbFixedSingle
    [green]    
    ' for purposes of example (and the fact I am currently not working on a large enough screen) set the clipping area as 1/2 scale of actual requirement[/green]
    ClipPic.Width = 475 * 2
    ClipPic.Height = 270 * 2
    
    PicScale = 100 ' Set initial scale in percent
    Set DisplayPic.Picture = SourcePic.Picture
    ScaleDisplayPic PicScale       
End Sub[/blue]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top