简体   繁体   中英

vb.net combine image from folder

there is a folder named "1"
"1" folder has around 1-100 image files in there
example file name: 000001.jpg 0000012.jpg 0000013.jpg ---> 000100.jpg

i want to combine all image from that folder (named 1)
and extract to one file (output_1.jpg) from 100 file to 1 file (Vertical)

but if there is 10 folder, combine all image from folder 1,2,3.....
and extract to one file per folder
output_1.jpg (all image from folder 1)
output_2.jpg (all image from folder 2)
output_3.jpg (all image from folder 3)
and more

folder structure:
-----c:\
----------folder1\
---------------------000001.jpg
---------------------000002.jpg

the combined image file will be extract to c:\ (not in folder1 or 2 or 3....)

this is my code, i have to add more code file by file to combine them (headache attack)

    Dim Img1 As Bitmap = Image.FromFile("C:\1\000001.jpg")
    Dim Img2 As Bitmap = Image.FromFile("C:\1\000002.jpg")
    Dim Img3 As Bitmap = Image.FromFile("C:\1\000003.jpg")
    Dim Img4 As Bitmap = Image.FromFile("C:\1\000004.jpg")
    Dim Img5 As Bitmap = Image.FromFile("C:\1\000005.jpg")

    Dim extract_img As Bitmap
    Dim Width As Integer
    Dim Height As Integer
    Dim x As Integer
    Dim y As Integer

    If Img1.Width > Img2.Width Then
        Width = Img1.Width
    Else
        Width = Img2.Width
    End If

    Height = Img1.Height + Img2.Height + Img3.Height + Img4.Height + Img5.Height
    extract_img = New Bitmap(Width, Height)

    For x = 0 To Img1.Width - 1
        For y = 0 To Img1.Height - 1
            extract_img.SetPixel(x, y, Img1.GetPixel(x, y))
        Next
    Next
    For x = 0 To Img2.Width - 1
        For y = 0 To Img2.Height - 1
            extract_img.SetPixel(x, y + Img1.Height, Img2.GetPixel(x, y))
        Next
    Next
    For x = 0 To Img3.Width - 1
        For y = 0 To Img3.Height - 1
            extract_img.SetPixel(x, y + Img1.Height + Img2.Height, Img3.GetPixel(x, y))
        Next
    Next
    For x = 0 To Img4.Width - 1
        For y = 0 To Img4.Height - 1
            extract_img.SetPixel(x, y + Img1.Height + Img2.Height + Img3.Height, Img4.GetPixel(x, y))
        Next
    Next
    For x = 0 To Img5.Width - 1
        For y = 0 To Img5.Height - 1
            extract_img.SetPixel(x, y + Img1.Height + Img2.Height + Img3.Height + Img4.Height, Img5.GetPixel(x, y))
        Next
    Next

    extract_img.Save("C:\output.jpg", System.Drawing.Imaging.ImageFormat.Jpeg)

You can get the image sizes from each file and work out how large the final image will be.

Then, as pointed out in a comment , you need to check that the final size is not too large.

Make a new bitmap to contain them all, then iterate over the files to draw them into the big one.

Finally, wrap it all up in an iteration over the subdirectories, something like this:

Imports System.Drawing.Imaging
Imports System.IO

Public Class Form1

    Function GetImageSize(fileName As String) As SizeF
        ' From "Getting image dimensions without reading the entire file"
        ' https://stackoverflow.com/questions/111345/getting-image-dimensions-without-reading-the-entire-file

        Dim dims As SizeF

        Using fs As New FileStream(fileName, FileMode.Open, FileAccess.Read)
            Using img = Image.FromStream(fs, False, False)
                dims = New SizeF(img.PhysicalDimension.Width, img.PhysicalDimension.Height)
            End Using
        End Using

        Return dims

    End Function

    Function GetOverallImageSize(srcDir As String) As Size
        Dim largestWidth As Single
        Dim overallHeight As Single

        For Each f In Directory.EnumerateFiles(srcDir, "*.jpg")
            Dim dims = GetImageSize(f)
            largestWidth = Math.Max(largestWidth, dims.Width)
            overallHeight += dims.Height
        Next

        Return New Size(CInt(largestWidth), CInt(overallHeight))

    End Function

    Sub MakeSprites(rootDir As String)
        For Each srcDir In New DirectoryInfo(rootDir).EnumerateDirectories

            Dim overallSize = GetOverallImageSize(srcDir.FullName)

            If overallSize.Width = 0 OrElse overallSize.Height = 0 Then
                MsgBox("No suitable image files found in " & srcDir.FullName)
                Continue For
            End If

            If overallSize.Width > 32767 OrElse overallSize.Height > 32767 Then
                MsgBox("Combined size of " & overallSize.ToString() & " is too large in " & srcDir.Name)
                Continue For
            End If

            Using bmp As New Bitmap(overallSize.Width, overallSize.Height, PixelFormat.Format24bppRgb)
                Dim g = Graphics.FromImage(bmp)
                Dim y = 0

                For Each f In Directory.EnumerateFiles(srcDir.FullName, "*.jpg")
                    Using im = Image.FromFile(f)
                        g.DrawImage(im, 0, y)
                        y += im.Height
                    End Using
                Next

                bmp.Save(Path.Combine(rootDir, srcDir.Name & ".png"), ImageFormat.Png)

            End Using

        Next

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim rootDir = "C:\temp\sprites"
        MakeSprites(rootDir)

    End Sub

End Class

So from this directory content:

在此处输入图像描述

I got the file "1.png":

在此处输入图像描述

If you really want to save the end result as a JPEG, you will probably want to read How to: Set JPEG Compression Level because the default is less than good quality. You would need to add

Private Shared Function GetEncoder(ByVal format As ImageFormat) As ImageCodecInfo

    Dim codecs As ImageCodecInfo() = ImageCodecInfo.GetImageDecoders()

    Dim codec As ImageCodecInfo
    For Each codec In codecs
        If codec.FormatID = format.Guid Then
            Return codec
        End If
    Next codec
    Return Nothing

End Function

and modify MakeSprites to be

Sub MakeSprites(rootDir As String)
    Dim jpegEncoder As ImageCodecInfo = GetEncoder(ImageFormat.Jpeg)
    Dim myEncoder As Imaging.Encoder = Imaging.Encoder.Quality
    Dim myEncoderParameters As New EncoderParameters(1)
    Dim myEncoderParameter As New EncoderParameter(myEncoder, 85L)
    myEncoderParameters.Param(0) = myEncoderParameter

    For Each srcDir In New DirectoryInfo(rootDir).EnumerateDirectories

        Dim overallSize = GetOverallImageSize(srcDir.FullName)

        If overallSize.Width = 0 OrElse overallSize.Height = 0 Then
            MsgBox("No suitable image files found in " & srcDir.FullName)
            Continue For
        End If

        If overallSize.Width > 32767 OrElse overallSize.Height > 32767 Then
            MsgBox("Combined size of " & overallSize.ToString() & " is too large in " & srcDir.Name)
            Continue For
        End If

        Using bmp As New Bitmap(overallSize.Width, overallSize.Height, PixelFormat.Format24bppRgb)
            Dim g = Graphics.FromImage(bmp)
            Dim y = 0

            For Each f In Directory.EnumerateFiles(srcDir.FullName, "*.jpg")
                Using im = Image.FromFile(f)
                    g.DrawImage(im, 0, y)
                    y += im.Height
                End Using
            Next

            bmp.Save(Path.Combine(rootDir, srcDir.Name & ".jpg"), jpegEncoder, myEncoderParameters)

        End Using

    Next

End Sub

You should be disappointed with the result - especially at the borders between images. It's just down to how JPEG-encoding works.

You will probably want to add some Try...Catches too for when things go wrong. And the MakeSprites method should probably be a function which returns a list of the problems it encountered rather than showing message boxes itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM