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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Saving Image with Time & Date 1

Status
Not open for further replies.

Error7

Programmer
Jul 5, 2002
656
GB
I am using URLDownloadToFile to download sequential frames from a video server and save them as jpg images.
Ideally I would like to display the time and date on each image before saving the jpg's, complete with the time & date displayed.
The only way I can think of to achieve this is to load the image into a Picture Box, print the time and date onto the picture, save it as a BMP then convert it to a jpg with DIWriteJpg.
Does anybody know of a better way to do this?


[gray]Experience is something you don't get until just after you need it.[/gray]
 
Should be plenty of code around that uses OleLoadPicture() to convert an image file formatted Byte array to a StdPicture. Probably even more around that uses GDI+ calls such as GdipSaveImageToStream() or GdipSaveImageToFile() to convert your altered StdPicture (after printing text) back to a JPEG either as a new Byte array or written to disk.

For a serious application you might want to bypass use of a PictureBox at all though, and work with a DIBSECTION selected into a memory DC. Again there ought to be plenty of sample code around.
 
Whatever way, you still have to produce a BMP somewhere of the time and date in the right shape, font and position before you add it to the picture pixels so the time taken is probably the same(or greater)
Do you have to have the time and date permanently in the picture or only seen when you view it in your application?
If the latter just append is as text in say a 24 bit block of text on the end of the file. It wont affect the picture.
When viewing the file also open it to a single large string and read the last 24 bytes to see the time in a separate label.
Then only people with your app can see the time and date.
 
>you still have to produce a BMP somewhere of the time and date in the right shape, font and position before you add it to the picture pixels

Is that what you've been doing, Ted? You do realise that Windows has several APIs that allow you to render text exactly where and how you want it directly into a device context?

E.g DrawText and DrawTextEx, or ExtTextOut
 
Thanks for your input Gents but I now realise that I was thinking ahead of myself. I can download the image as a jpg, load it inot a picture box, add the time and date with:
Picture1.Font.Size = 12
Picture1.FontBold = True
Picture1.Font.Name = "arial"
Picture1.ForeColor = vbBlack
Picture1.CurrentX = 200
Picture1.CurrentY = 100
Picture1.Print myTime & myDate

then just save it as a bmp. I don't actually need to convert it into a jpg. [thumbsup2]

Simples

[gray]Experience is something you don't get until just after you need it.[/gray]
 
What I meant was you still have to define the "image" of the clock whether it be in graphics or code which probably takes around the same amount of code (or even more). The code method is more elegant (and mysterious) from a programmer's point of view.

If you save a BMP of what was originally a jpg, the file will be many times larger depending on the size of the picturebox on your screen.
In one test I recently did I took a 1mb 640x480 pixel BMP, converted it to a jpg 25kb with hardly any visible degredation without magnifying, then loaded it back into a 640x480 picturebox, saved it as BMP which again produced a 1mb file, a huge increase.
The JPG conversion code I used was courtesy of strongm (as usual!) and is posted somewhere in this forum.

I still don't like smartphones.
 
In this case size doesn't matter. [blush] After downloading a sequence of jpg's from my video server, I add the time and date of the event and save as BMP's.
I then render the BMP sequence as an AVI file and then I can delete all the BMP's. This is the end result: Link
My new video server has a much better frame rate and will output AVI files directly but unfortunately I haven't got round to installing it yet. [sad]

[gray]Experience is something you don't get until just after you need it.[/gray]
 
What image, Ted? The OP only mentions wanting a text timestamp, as far as I can see.
 
I assumed he wanted this time stamp to be visible as an image on the screen regardless of the method.

In my imagination I always visualise something that creates an eventual image as being a sort of "image in space" before it is actually drawn on the screen - even a simple Print statement. It could be instructions as to how to draw/move from pixel to pixel but at some stage it has to translate to the equivalent of an image created the same pixel size as the background picture (even a JPG)

So I thought that both methods would require a similar number of "instructions" to show it on the final computer screen
If one were quicker, if the resultant image plus time/date is to be saved, the time to save on disk would be far greater than any processing speed difference.
If it is to be viewed only, then you only need the text tacked onto the file and you can show it in any size or format you like and also use it for sorting or secrecy purposes.

I also apply a similar philosophy to music in that I can play a tune by ear after hearing it only a few times. I can hear and remember the melody and the harmony equally and as a result, translate it to any key. It's all done by aural "visualisation".

There is one aspect of superimposing text on picture that has always intrigued me. If you put white text over say a snow scene you can't read the letters where there is snow.
Good video editors usually allow black edges and shadows around text. I have often wondered how they do this.
 
>I have often wondered how they do this

In Windows it would simply be by setting the stroke and fill settings appropriately
 
"Good video editors usually allow black edges and shadows around text. I have often wondered how they do this."
My initial title overlay in the video is created in the video editing programme I use and this adds a shadow of any depth or colour.
The shadow in the time and date overlay that I added in VB is done by using a slight offset to the x and y co-ordinates.

Picture1.Font.Size = 12
Picture1.FontBold = True
Picture1.Font.Name = "arial"
Picture1.ForeColor = vbBlack
Picture1.CurrentX = 200
Picture1.CurrentY = 100
Picture1.Print "Camera " & Format(CamNum, "00") & " " & Left(RecordTime, 8) & " " & Mid(RecordTime, 10, 2) & "/" & Mid(RecordTime, 13, 2) & "/" & Right(RecordTime, 4)

Picture1.ForeColor = vbWhite
Picture1.CurrentX = 170
Picture1.CurrentY = 70
Picture1.Print "Camera " & Format(CamNum, "00") & " " & Left(RecordTime, 8) & " " & Mid(RecordTime, 10, 2) & "/" & Mid(RecordTime, 13, 2) & "/" & Right(RecordTime, 4)

[gray]Experience is something you don't get until just after you need it.[/gray]
 
Ah yes, I've done that before but it only gives a black edge on 2 sides. You need a character that is magnified in all directions to the original otherwise the top and left of the character merge into the background if it is the same color and intensity.

I suspect they do it by having slightly different shaped fonts for the black and white.

I once started to do this but it became very tedious. I needed some way of doing it automatically to a variety of fonts.
 
Even if the text is the same colour as the background, if the shadow is deep enough the text is still readable, no need for a full outline of each character.

[gray]Experience is something you don't get until just after you need it.[/gray]
 
Ted, go to 0:31 of my YouTube video for an example of this.

[gray]Experience is something you don't get until just after you need it.[/gray]
 
Link

[gray]Experience is something you don't get until just after you need it.[/gray]
 
>I suspect they do it by having slightly different shaped fonts for the black and white

If they were offsetting - but they don't. They generally much the technique I mentioned above - having a different stroke and fill.

>I needed some way of doing it automatically to a variety of fonts.

It's really not hard
You'll need a form with a picturebox and 3command button. Copy and paste the following code:

Code:
[blue]Option Explicit

Private Sub Command1_Click()
    Picture1.Cls
    DrawText Picture1.hDC, "Example1", 0, 0, , True
End Sub

Private Sub Command2_Click()
    Picture1.Cls
    DrawText Picture1.hDC, "Example2", 0, 0, , False
End Sub

Private Sub Command3_Click()
    Picture1.Cls
    DrawText Picture1.hDC, "Example3", 0, 0, False, True
End Sub

Private Sub Form_Load()
    Picture1.FillColor = vbWhite
    Picture1.ForeColor = vbBlack
    Picture1.DrawWidth = 2
    Picture1.Font = "Lucida Console" [green]' Needs to be an outline font, because we cannot stroke and fill an non-outline font[/green]
    Picture1.Font.Size = 48
End Sub[/blue]

Then chuck the following code in a module:
Code:
[blue]Option Explicit

Private Declare Function BeginPath Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function EndPath Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function TextOut Lib "gdi32" Alias "TextOutA" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal lpString As String, ByVal nCount As Long) As Long
Private Declare Function StrokeAndFillPath Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function StrokePath Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function FillPath Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function GetBkMode Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function SetBkMode Lib "gdi32" (ByVal hDC As Long, ByVal nBkMode As Long) As Long
' Background Modes
Private Const TRANSPARENT = 1
Private Const OPAQUE = 2
Public Sub DrawText(ByVal Target_hDC As Long, ByVal Text As String, ByVal X As Long, ByVal Y As Long, Optional m_Filled As Boolean = True, Optional m_Outlined As Boolean = False)
    Dim oldBkMode As Long

    If Target_hDC Then
        oldBkMode = SetBkMode(Target_hDC, TRANSPARENT)
        [green]' create the path within the DC[/green]
        Call BeginPath(Target_hDC)
        TextOut Target_hDC, X, Y, Text, Len(Text)
        Call EndPath(Target_hDC)
        
        If m_Outlined And m_Filled Then
                StrokeAndFillPath Target_hDC
        ElseIf m_Filled Then
            FillPath Target_hDC
        ElseIf m_Outlined Then
            StrokePath Target_hDC
        End If
        Call SetBkMode(Target_hDC, oldBkMode)
    End If
End Sub[/blue]

 
Thanks I'll try it when I have the chance.
When I mentioned different fonts for the same character I didn't mean they were offset otherwise you'd get the same problem as Error7's method.
With my suggested method I took an existing font in a font editor and created a clone of it shifting the edges by a few pixels in all four ways so it was bigger but had the same character spacing when a number of characters are printed. This became the black letter over which I placed the white one giving a nice crisp black border to all sides of the letter.
That's why it became tedious! All very graphical and no code therefore uninteresting to a programmer?
 
And my example code will do that all for you. No tedium at all. Just easy.
 
Oops - you may want to add

Picture1.FillStyle = vbSolid

to the Form_Load event
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top