Click here to Skip to main content
15,890,438 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Can this code be changed to winforms VB instead of WPF? The parts I need changed are the Run and CreateImage subs and a Import or two.
' xxx = areas that need to be changed.

This class was originally written in C# WPF VS2008 Pro by Julien Mancini for
his excellent version of a Logon Background Changer.

This class is used to get a *.bmp or *.png or *.jpg file as close to 256kb
as possible so the Windows 7 LogonUI can use it.

VB
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.IO
Imports System.Windows.Media.Imaging ' xxx
Imports System.Windows.Media         ' xxx
Imports System.Windows
Imports System.ComponentModel
Imports System.Threading

Class ImagesCreation
    ''' <summary>
    ''' Resolutions of the pictures that the Logon UI is going to look for.
    ''' Note : the vertical wallpapers are useful for portrait screens (i.e Tablet PCs, ...) '     { 1280, 1024 },
    ''' </summary>
    Public Shared imgResolutions As Integer(,) = New Integer(,) {{1280, 960}, {1024, 768}, {1600, 1200}, {1440, 900}, {1920, 1200}, {1280, 768}, _
        {1360, 768}, {1024, 1280}, {960, 1280}, {900, 1440}, {768, 1280}, {768, 1360}}
    ''' <summary>
    ''' Path of the original picture
    ''' </summary>
    Private imgPath As String
    Public Sub New(imgPath As String)
        Me.imgPath = imgPath
    End Sub
    ''' <summary>
    ''' Creates the background at each supported resolution
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="args"></param>
    Public Sub run(sender As Object, args As DoWorkEventArgs)
        Thread.Sleep(200)
        Dim bgWorker As BackgroundWorker = TryCast(sender, BackgroundWorker)
        Try
            Dim bmpSrc As New CachedBitmap(New BitmapImage(New Uri(imgPath)), BitmapCreateOptions.None, BitmapCacheOption.OnLoad)                  ' xxx
            For i As Integer = 0 To imgResolutions.GetLength(0) - 1
                Dim w As Integer = imgResolutions(i, 0)
                Dim h As Integer = imgResolutions(i, 1)
                createImage(bmpSrc, w, h, "background" & w & "x" & h & ".jpg")                        ' xxx
                bgWorker.ReportProgress(i + 1)
            Next
            Dim screenWidth As Integer = CInt(Math.Truncate(SystemParameters.PrimaryScreenWidth))
            Dim screenHeight As Integer = CInt(Math.Truncate(SystemParameters.PrimaryScreenHeight))
            createImage(bmpSrc, screenWidth, screenHeight, "backgroundDefault.jpg")                                   ' xxx
                ' 100 means we have finished, no userState parameter means the operation has been successful
            bgWorker.ReportProgress(100)
        Catch ex As Exception
                ' userState parameter has been defined -> operation failed
            bgWorker.ReportProgress(100, ex)
        End Try
    End Sub
    ''' <summary>
    ''' Creates a jpg file which is as close as sub 256kb as possible. (262144 bytes)
    ''' Truncates it if the ratio is not the same as the resolution needed
    ''' </summary>
    ''' <param name="bmpSrc">original bitmap</param>
    ''' <param name="w">Width</param>
    ''' <param name="h">Height</param>
    ''' <param name="filename">destination file name</param>
    Private Sub createImage(bmpSrc As BitmapSource, w As Integer, h As Integer, filename As String)                                     ' xxx
        Dim srcW As Integer = bmpSrc.PixelWidth         ' xxx
        Dim srcH As Integer = bmpSrc.PixelHeight        ' xxx
        Dim ratioSrc As Double = CDbl(srcW) / srcH
        Dim ratioDest As Double = CDbl(w) / h
        Dim newW As Integer
        Dim newH As Integer
        If ratioDest < ratioSrc Then
            newH = srcH
            newW = CInt(Math.Truncate(srcW / ratioSrc * ratioDest))
        Else
            newW = srcW
            newH = CInt(Math.Truncate(srcH * ratioSrc / ratioDest))
        End If
        Dim bmp As New CroppedBitmap(bmpSrc, New Int32Rect((srcW - newW) \ 2, (srcH - newH) \ 2, newW, newH))     ' xxx
        Dim drawingVisual As New DrawingVisual()     ' xxx
        Dim drawingContext As DrawingContext = drawingVisual.RenderOpen()   ' xxx
        drawingContext.DrawImage(bmp, New Rect(0, 0, w, h))   ' xxx
        drawingContext.Close()                                ' xxx
        'Allows us to do a bitmap rendering of a WPF Visual
        Dim tg As New RenderTargetBitmap(w, h, 96, 96, PixelFormats.Pbgra32) ' xxx
        tg.Render(drawingVisual)                                             ' xxx
        Dim found As Boolean = False
        'has the best quality possible been found?
        Dim ms As MemoryStream = Nothing
        Dim quality As Integer = 94
        Dim [step] As Char = "d"C
        'd = decrease quality, i = increase, e = end
        Dim delta As Integer = -8
        Dim topInterval As Integer = 101
        While Not found
            If ms IsNot Nothing Then
                ms.Close()
            End If
            ms = New MemoryStream()
            Dim encoder As New JpegBitmapEncoder()    ' xxx?
            quality += delta
            encoder.QualityLevel = quality
            encoder.Frames.Add(BitmapFrame.Create(tg)) ' xxx
            encoder.Save(ms)
            Dim pos As Long = ms.Position
            If pos < 256 * 1000 Then
                'the image file size is small enough
                If quality = 100 Then
                    found = True
                ElseIf [step] = "d"C Then
                    ' maybe we decreased the quality too much
                    delta = Math.Max(1, Math.Abs(delta \ 2))
                        ' increasing quality
                    [step] = "i"C
                ElseIf [step] = "i"C Then
                    delta = Math.Max(1, Math.Abs(delta \ 2))
                    If delta = 1 AndAlso topInterval = quality + delta Then
                        found = True
                    End If
                ElseIf [step] = "e"C Then
                    'finished
                    found = True
                End If
            Else
                'the image file size is too big
                If [step] = "i"C AndAlso delta = 1 Then
                    ' quality is just 1 unit above the best quality
                    ' we can afford to keep a sub 256kb image
                    [step] = "e"C
                    ' the search of the best quality is finished
                    delta = -1
                ElseIf delta <> -8 Then
                    delta = -Math.Max(1, Math.Abs(delta \ 2))
                    [step] = "d"C
                End If
                    ' if delta == initial delta (-8) -> we haven't increased yet, we can continue descreasing with a large delta
                topInterval = quality
            End If
        End While
        'writes the file : may fail if the user has not the right to create a file. In this case an exception
        'will be thrown and catched by the application. The user will then be prompted by an UAC window, and the operation
        'will be launched again.
        ms.Position = 0
        Dim folder As String = Environment.GetFolderPath(Environment.SpecialFolder.System) & "\oobe\info\backgrounds\"
        If Not Directory.Exists(folder) Then
            Directory.CreateDirectory(folder)
        End If
        Dim fs As New FileStream(folder & filename, FileMode.OpenOrCreate, FileAccess.Write)
        fs.SetLength(0)
        'truncates the file if it already exists
        Dim octet As Integer
        While (InlineAssignHelper(octet, ms.ReadByte())) <> -1
            fs.WriteByte(CByte(octet))
        End While
        fs.Close()
        ms.Close()
    End Sub
    Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
        target = value
        Return value
    End Function
End Class
Posted
Comments
Dave Kreskowiak 1-Jun-11 10:10am    
Yeah, it can be changed. All you have to do is understand the goals of the code and rewrite however you want. We're not going to rewrite it for you.

Why do you have to convert the code to work with Windoes Forms?? Why not just use the code as is?
Sergey Alexandrovich Kryukov 1-Jun-11 13:30pm    
Agree, this is not clear.
Next OP question (below) was about mixing them.
In my answer I mentioned all available opportunities.

I would advise to avoid the interop.
--SA
rspercy65 1-Jun-11 13:15pm    
I did not think you could mix WPF code with WinForms.
Sergey Alexandrovich Kryukov 1-Jun-11 13:28pm    
You can mix them in both directions. Please see my answer.
--SA

1 solution

Answering a follow-up question:

Yes, you can either host a Windows Forms control in WPF or host a WPF control in Windows Forms.
This is the top-level description of the interoperability architecture:
http://msdn.microsoft.com/en-us/library/ms742474.aspx[^]

Here you can find walkthrough for both cases:
http://msdn.microsoft.com/en-us/library/ms750944.aspx[^],
http://msdn.microsoft.com/en-us/library/ms742215.aspx[^].

I would suggest you re-write application for the library which better suites your goal. Yes, you will have to do it by yourself, but I don't see anything difficult. Pay attention that System.Windows.Drawing is designed to work with Forms only. You can also use it with WPF, but for this purpose you will need to use interoperaion as well. WPF has its own ways to work with images, it's the best not to mix them.

To alleviate all those UI problems, you need to isolate both universal and application-specific parts of your code from you UI very thoroughly. I suggest you learn and analyze the well-known architectural patters related to this goal I list below:

MVVM — Model View View Model,
http://en.wikipedia.org/wiki/Model_View_ViewModel[^],

MVC — Model-View-Controller,
http://en.wikipedia.org/wiki/Model-view-controller[^]),

MVA — Model-View-Adapter,
http://en.wikipedia.org/wiki/Model–view–adapter[^],

MVP — Model-View-Presenter,
http://en.wikipedia.org/wiki/Model-view-presenter[^].
Pay attention for the motivation of those architectures. If you understand it, you would be able to create better design ideas.

—SA
 
Share this answer
 
Comments
rspercy65 1-Jun-11 13:35pm    
I can use it. All I need is the correct Namespaces and Classes for the Imports. I already to go.
THNX Alot guys.
Sergey Alexandrovich Kryukov 1-Jun-11 14:07pm    
Sure. Thank for accepting the answer.
Good luck, call again.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900