Separate Horizontal images and vertical into separate folders...

Separate Horizontal images and vertical into separate folders...
is there a way we can script to move images into 2 folders as Horizontal ones and vertical ones?
Attached sample folder

Thanks
127-Hours.zip
mtthompsonsAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jeff DarlingDeveloper AnalystCommented:
How would you define Horizontal or Vertical?

Below are the names and sizes.  size represented as (width x height)

03a5dc35-007c-4cca-a96e-fa1e3292a9aa.jpg	2000x1305
22a0ef87-7075-49cb-9cb3-9cd5c0a93bbb.jpg	2000x1333
45cfd1f3-37f1-4792-b6d0-5eef28fea437.jpg	900x600
64b35bc2-8ccd-45d9-8478-448cd89d66a4.jpg	1600x1066
583c4f4e-e3e7-499b-82f6-21d6bdd9c740.jpg	1600x1066
b1f5e255-6600-4c75-9f05-3932cd29bab1.jpg	1280x768
c1906a6c-9ca5-4563-8866-ada4b97b81d1.jpg	1600x1066
d6b3220e-cc2b-45f5-accb-736a02a29d61.jpg	400x300
ddc27fa1-b491-46cb-84ab-5ec8d5100c12.jpg	1280x1896
e6ae180d-7398-4ec1-b6ff-a793e74328e7.jpg	616x411

Open in new window

0
mtthompsonsAuthor Commented:
Yes right but i have no clue about that... Anyways you can suggest?
0
Jeff DarlingDeveloper AnalystCommented:
It might be the jpg orientation property, but that property is not set on any of those files :(
0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

mtthompsonsAuthor Commented:
Anyways to retrieve jpeg orientation property... Like restore?
0
Bill PrewCommented:
There is metadata stored in jpg files normally in the "EXIF" section of the jpg file, but these files seem to have very little info in those fields.  For most current digital cameras they can and do store a lot of useful info in there, so wondering where these pictures of yours came from?  And if they were processed through some other program that might have stripped out EXIF info?  Do you have the original jpg files.

Based on the EXIF info in these files I don't see a surefire way to know if the pictures are portrait or landscape.  Unless you wanted to assume that all pictures where the height is greater than the width should be marked as portrait, and that it was created that way.  Based on your small sample that seems to be true, but not sure if that will hold up for the larger set of pictures.

If you want to take that approach a small VBS could do the job, we can work that up.

~bp
0
Bill PrewCommented:
Here is a sample VBS that might get you started if the approach above works.  Adjust the folder paths as needed.  Also, note that for testing I have commented out the actual copy.  Microsoft tends to change the indexes to the fields in the file metadata, and I think I may have slightly different values since I am on Windows 10 now.  I seem to remember these being different.  Let me know what version of Windows you will run this on and I can help you determine these values.  But you can test with my values and see what the display shows on the screen (run with CSCRIPT from a command line), and see if the width and height values look right or are nonsense.

' May vary depending on Windows versions, I tested on Win10 and Win7 and saw the offsets below, adjust commenting as needed
' ***** WINDOWS 7 *****
'Const ExifWidth = 162
'Const ExifHeight = 164
' ***** WINDOWS 10 *****
Const ExifWidth = 169
Const ExifHeight = 171

'Create needed objects
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")

' Define folders to work with
strBaseDir = objFSO.GetAbsolutePathName("pics")
strSortSquare = strBaseDir & "\" & "square"
strSortVertical = strBaseDir & "\" & "portrait"
strSortHorizontal = strBaseDir & "\" & "landscape"

' Make sure base folder exists, exit if not
If Not objFSO.FolderExists(strBaseDir) Then 
   Wscript.Echo "Base folder missing: """ & strBaseDir & """."
   Wscript.Quit
End If

' Make sure sorting folders exist, create if needed
If Not objFSO.FolderExists(strSortSquare) Then objFSO.CreateFolder(strSortSquare)
If Not objFSO.FolderExists(strSortVertical) Then objFSO.CreateFolder(strSortVertical)
If Not objFSO.FolderExists(strSortHorizontal) Then objFSO.CreateFolder(strSortHorizontal)

' Access base folder for processing
Set objBaseDir = objFSO.GetFolder(strBaseDir)
Set objNameSpace = objShell.NameSpace(strBaseDir)

' Process all "*.jpg" files in base folder
For Each objFile in objBaseDir.Files
   If LCase(Right(objFile.Name, 4)) = ".jpg" Then

      ' Get image width and height from file metadata
      Set objFileItem = objNameSpace.ParseName(objFile.Name)
      intWidth = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifWidth))
      intHeight = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifHeight))

      ' Determine orientation based on dimensions
      Select Case True
        Case intWidth > intHeight
           strDestDir = strSortHorizontal
        Case intWidth < intHeight
           strDestDir = strSortVertical
        Case Else
           strDestDir = strSortSquare
      End Select

      ' Copy file to appropriated sorted folder
      Wscript.Echo intWidth & "," & intHeight & "," & strDestDir & "," & objFile.Name
      ' objFile.Copy strDestDir & "\"

   End If
Next

Function GetNumber(strInfo)
   ' Extract just the first "word" from the string, and remove first character, and then convert to integer
   GetNumber = 0
   On Error Resume Next
   GetNumber = CInt(Mid(Split(strInfo, " ")(0), 2))
   On Error Goto 0
End Function

Open in new window

~bp
1
Jeff DarlingDeveloper AnalystCommented:
0
Jeff DarlingDeveloper AnalystCommented:
0
Bill PrewCommented:
EE might strip EXIF if you post an image directly, but I can't imagine it messed with the files inside a ZIP file, as the original post had.  You?

~bp
0
Jeff DarlingDeveloper AnalystCommented:
I tried that VBScript but found that it did not return the width and height on my system.  

I modified it slightly to use  WIA.ImageFile

Bill, I used your code, just added the WIA.ImageFile function.

' May vary depending on Windows versions, I tested on Win10 and Win7 and saw the offsets below, adjust commenting as needed
' ***** WINDOWS 7 *****
Const ExifWidth = 162
Const ExifHeight = 164
' ***** WINDOWS 10 *****
'Const ExifWidth = 169
'Const ExifHeight = 171

'Create needed objects
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")

' Define folders to work with
strBaseDir = objFSO.GetAbsolutePathName("e:\img")
strSortSquare = strBaseDir & "\" & "square"
strSortVertical = strBaseDir & "\" & "portrait"
strSortHorizontal = strBaseDir & "\" & "landscape"

' Make sure base folder exists, exit if not
If Not objFSO.FolderExists(strBaseDir) Then 
   Wscript.Echo "Base folder missing: """ & strBaseDir & """."
   Wscript.Quit
End If

' Make sure sorting folders exist, create if needed
If Not objFSO.FolderExists(strSortSquare) Then objFSO.CreateFolder(strSortSquare)
If Not objFSO.FolderExists(strSortVertical) Then objFSO.CreateFolder(strSortVertical)
If Not objFSO.FolderExists(strSortHorizontal) Then objFSO.CreateFolder(strSortHorizontal)

' Access base folder for processing
Set objBaseDir = objFSO.GetFolder(strBaseDir)
Set objNameSpace = objShell.NameSpace(strBaseDir)

' Process all "*.jpg" files in base folder
For Each objFile in objBaseDir.Files
   If LCase(Right(objFile.Name, 4)) = ".jpg" Then

      ' Get image width and height from file metadata
      Set objFileItem = objNameSpace.ParseName(objFile.Name)
      'intWidth = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifWidth))
      'intHeight = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifHeight))
      
      intArrWIA = Split(GetWIAImageFileInfo(objBaseDir & "\" & objFile.Name),"x")
      
      intWIAWidth = intArrWIA(0)
      intWIAHeight = intArrWIA(1)

      ' Determine orientation based on dimensions
      Select Case True
        Case intWIAWidth > intWIAHeight
           strDestDir = strSortHorizontal
        Case intWIAWidth < intWIAHeight
           strDestDir = strSortVertical
        Case Else
           strDestDir = strSortSquare
      End Select



      ' Copy file to appropriated sorted folder
      'Wscript.Echo intWidth & "," & intHeight & "," & strDestDir & "," & objFile.Name
      ' objFile.Copy strDestDir & "\"
      WScript.Echo intWIAWidth & "," & intWIAHeight & "," & strDestDir & "," & objFile.Name

   End If
Next

Function GetNumber(strInfo)
   ' Extract just the first "word" from the string, and remove first character, and then convert to integer
   GetNumber = 0
   On Error Resume Next
   GetNumber = CInt(Mid(Split(strInfo, " ")(0), 2))
   On Error Goto 0
End Function

Function GetWIAImageFileInfo(strFilename)
   Dim oImg
   Set oImg = WScript.CreateObject("WIA.ImageFile")
   oImg.LoadFile strFilename
   GetWIAImageFileInfo =  oImg.Width & "x" & oImg.Height
End Function

Open in new window


Results

2000,1305,E:\img\landscape,03a5dc35-007c-4cca-a96e-fa1e3292a9aa.jpg
2000,1333,E:\img\landscape,22a0ef87-7075-49cb-9cb3-9cd5c0a93bbb.jpg
900,600,E:\img\landscape,45cfd1f3-37f1-4792-b6d0-5eef28fea437.jpg
1600,1066,E:\img\landscape,64b35bc2-8ccd-45d9-8478-448cd89d66a4.jpg
1600,1066,E:\img\landscape,583c4f4e-e3e7-499b-82f6-21d6bdd9c740.jpg
1280,768,E:\img\portrait,b1f5e255-6600-4c75-9f05-3932cd29bab1.jpg
1600,1066,E:\img\landscape,c1906a6c-9ca5-4563-8866-ada4b97b81d1.jpg
400,300,E:\img\landscape,d6b3220e-cc2b-45f5-accb-736a02a29d61.jpg
1280,1896,E:\img\portrait,ddc27fa1-b491-46cb-84ab-5ec8d5100c12.jpg
616,411,E:\img\landscape,e6ae180d-7398-4ec1-b6ff-a793e74328e7.jpg
447,640,E:\img\portrait,jeffld-large.jpg
2448,3264,E:\img\portrait,IMG_20150912_122114.jpg
447,640,E:\img\portrait,jeffld-large-test.jpg

Open in new window

0
Jeff DarlingDeveloper AnalystCommented:
Attaching zipped test image known to have EXIF info.
IMG_20150912_122114.zip
0
Jeff DarlingDeveloper AnalystCommented:
The exif data remained intact inside the above test zip file.  I can only guess that the exif info on the 127-files.zip jpg files got stripped somewhere else along the way.
0
Bill PrewCommented:
Agreed.

~bp
0
Bill PrewCommented:
On the script, what version of Windows did you run on, and did you try both pairs of the constants?

~bp
0
Jeff DarlingDeveloper AnalystCommented:
I'm on Windows 7 professional 32bit.

These lines of code return Zero.

intWidth = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifWidth))
      intHeight = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifHeight))

Open in new window

0
Jeff DarlingDeveloper AnalystCommented:
No, sorry, I missed that. I did not run with both constants.

These lines of code  works with the Windows 7 Constants.

intWidth = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifWidth))
intHeight = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifHeight))

Open in new window

0
Bill PrewCommented:
Okay, good.

~bp
0
mtthompsonsAuthor Commented:
Sorry for the delay

When i run the script i get this
---------------------------
Windows Script Host
---------------------------
1496,847,G:\img\portrait,5-Idiots.jpg
---------------------------
OK  
---------------------------


Once its done for all 10 images i have to test i can see 3 folders but no images within them.... Should i expect them to move into the 3 folders ?
0
Bill PrewCommented:
You will need to remove the leading quote on the objFile.Copy line for it to copy files, I left that commented out for testing.

~bp
0
mtthompsonsAuthor Commented:
Can i have the full code please
0
Jeff DarlingDeveloper AnalystCommented:
Did you try the code that Bill supplied?  

Code - a40987133
0
Bill PrewCommented:
Full code removing comment from copy.

' May vary depending on Windows versions, I tested on Win10 and Win7 and saw the offsets below, adjust commenting as needed
' ***** WINDOWS 7 *****
'Const ExifWidth = 162
'Const ExifHeight = 164
' ***** WINDOWS 10 *****
Const ExifWidth = 169
Const ExifHeight = 171

'Create needed objects
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")

' Define folders to work with
strBaseDir = objFSO.GetAbsolutePathName("pics")
strSortSquare = strBaseDir & "\" & "square"
strSortVertical = strBaseDir & "\" & "portrait"
strSortHorizontal = strBaseDir & "\" & "landscape"

' Make sure base folder exists, exit if not
If Not objFSO.FolderExists(strBaseDir) Then 
   Wscript.Echo "Base folder missing: """ & strBaseDir & """."
   Wscript.Quit
End If

' Make sure sorting folders exist, create if needed
If Not objFSO.FolderExists(strSortSquare) Then objFSO.CreateFolder(strSortSquare)
If Not objFSO.FolderExists(strSortVertical) Then objFSO.CreateFolder(strSortVertical)
If Not objFSO.FolderExists(strSortHorizontal) Then objFSO.CreateFolder(strSortHorizontal)

' Access base folder for processing
Set objBaseDir = objFSO.GetFolder(strBaseDir)
Set objNameSpace = objShell.NameSpace(strBaseDir)

' Process all "*.jpg" files in base folder
For Each objFile in objBaseDir.Files
   If LCase(Right(objFile.Name, 4)) = ".jpg" Then

      ' Get image width and height from file metadata
      Set objFileItem = objNameSpace.ParseName(objFile.Name)
      intWidth = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifWidth))
      intHeight = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifHeight))

      ' Determine orientation based on dimensions
      Select Case True
        Case intWidth > intHeight
           strDestDir = strSortHorizontal
        Case intWidth < intHeight
           strDestDir = strSortVertical
        Case Else
           strDestDir = strSortSquare
      End Select

      ' Copy file to appropriated sorted folder
      Wscript.Echo intWidth & "," & intHeight & "," & strDestDir & "," & objFile.Name
      objFile.Copy strDestDir & "\"

   End If
Next

Function GetNumber(strInfo)
   ' Extract just the first "word" from the string, and remove first character, and then convert to integer
   GetNumber = 0
   On Error Resume Next
   GetNumber = CInt(Mid(Split(strInfo, " ")(0), 2))
   On Error Goto 0
End Function

Open in new window

~bp
0
mtthompsonsAuthor Commented:
Sorry for the delay will test today
0
mtthompsonsAuthor Commented:
I get this
All show up as 0,0

---------------------------
Windows Script Host
---------------------------
0,0,G:\Hindi 501-800\square,Badmaash-Company.jpg
---------------------------
OK  
---------------------------
0
Bill PrewCommented:
As mentioned earlier in this thread, if you are not on Windows 10, try changing these lines:

' ***** WINDOWS 7 *****
'Const ExifWidth = 162
'Const ExifHeight = 164
' ***** WINDOWS 10 *****
Const ExifWidth = 169
Const ExifHeight = 171

Open in new window

to this:

' ***** WINDOWS 7 *****
Const ExifWidth = 162
Const ExifHeight = 164
' ***** WINDOWS 10 *****'
Const ExifWidth = 169
'Const ExifHeight = 171

Open in new window

~bp
0
mtthompsonsAuthor Commented:
Now i get this
---------------------------
Windows Script Host
---------------------------
1500,750,G:\Hindi 501-800\landscape,Aa-Dekhen-Zara.jpg
---------------------------
OK  
---------------------------

Can you enable the way that it seperates into 2 folders and no popup shows when it does this
0
Bill PrewCommented:
Just remove this line:

Wscript.Echo intWidth & "," & intHeight & "," & strDestDir & "," & objFile.Name


~bp
0
mtthompsonsAuthor Commented:
Great thanks works great..

I have 1000+ folders which has 30 to 300 images each

Can we create folders in each as Portrait and square and do the job for all folders
0
Bill PrewCommented:
Are all folders to processed under a single parent folder?  So we would process all subfolders of a starting base folder?

Are there just one level of folders, or could there be several levels under the base folder that need to be drilled into?

~bp
0
Bill PrewCommented:
Also, in each of the individual folders where the pictures are to be sorted, would you always want the three subfolders added (square, portrait, landscape) even if they could be empty if no pictures of that format existed in that folder.  Or do you want the subfolder only created when a picture of that format is found that needs to be moved?

~bp
0
mtthompsonsAuthor Commented:
yes all are in one folder
G:\images\
Here i have 100's of folders

Only if we have varients we can have folders created else no folders
0
Bill PrewCommented:
Okay, give this a test, should do what you described.

' May vary depending on Windows versions, I tested on Win10 and Win7 and saw the offsets below, adjust commenting as needed
' ***** WINDOWS 7 *****
Const ExifWidth = 162
Const ExifHeight = 164
' ***** WINDOWS 10 *****
'Const ExifWidth = 169
'Const ExifHeight = 171

' Define names for the sorted pictures folders
Const SquareFolder = "square"
Const VerticalFolder = "vertical"
Const HorizontalFolder = "landscape"

'Create needed objects
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")

' Define base folder to start from
strBaseDir = objFSO.GetAbsolutePathName("G:\Images")

' Make sure base folder exists, exit if not
If Not objFSO.FolderExists(strBaseDir) Then 
   Wscript.Echo "Base folder missing: """ & strBaseDir & """."
   Wscript.Quit
End If

' Start the process at the base folder
ProcessFolder objFSO.GetFolder(strBaseDir)
'strSortSquare = "square"
'strSortVertical = "portrait"
'strSortHorizontal = "landscape"

Wscript.Quit


Sub ProcessFolder(objFolder)

   If objFolder.Name <> SquareFolder And objFolder.Name <> VerticalFolder And objFolder.Name <> HorizontalFolder Then

      Set objNameSpace = objShell.NameSpace(objFolder.Path)

      ' Process all "*.jpg" files in base folder
      For Each objFile in objFolder.Files
         If LCase(Right(objFile.Name, 4)) = ".jpg" Then

            ' Get image width and height from file metadata
            Set objFileItem = objNameSpace.ParseName(objFile.Name)
            intWidth = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifWidth))
            intHeight = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifHeight))

            ' Determine orientation based on dimensions
            Select Case True
              Case intWidth > intHeight
                 strDestDir = objFolder.Path & "\" & HorizontalFolder & "\"
              Case intWidth < intHeight
                 strDestDir = objFolder.Path & "\" & VerticalFolder & "\"
              Case Else
                 strDestDir = objFolder.Path & "\" & SquareFolder & "\"
            End Select

            ' Copy file to appropriated sorted folder
            ' Wscript.Echo intWidth & "," & intHeight & "," & strDestDir & "," & objFile.Name
            If Not objFSO.FolderExists(strDestDir) Then
               objFSO.CreateFolder(strDestDir)
            End If
            objFile.Copy strDestDir

         End If
      Next

      ' Drill down into any subfolders
      For Each objSubFolder in objFolder.Subfolders
         ProcessFolder(objSubFolder)
      Next
   End If

End Sub

Function GetNumber(strInfo)
   ' Extract just the first "word" from the string, and remove first character, and then convert to integer
   GetNumber = 0
   On Error Resume Next
   GetNumber = CInt(Mid(Split(strInfo, " ")(0), 2))
   On Error Goto 0
End Function

Open in new window

~bp
0
mtthompsonsAuthor Commented:
Thanks a lot it works awesome... Can we move the images to these folders so i can save space and know if any did not move for some reason...
0
Bill PrewCommented:
Sure, basically we can just change the COPY to a MOVE method, and as long as the file doesn't exist already in the destination then all should be good.

' May vary depending on Windows versions, I tested on Win10 and Win7 and saw the offsets below, adjust commenting as needed
' ***** WINDOWS 7 *****
Const ExifWidth = 162
Const ExifHeight = 164
' ***** WINDOWS 10 *****
'Const ExifWidth = 169
'Const ExifHeight = 171

' Define names for the sorted pictures folders
Const SquareFolder = "square"
Const VerticalFolder = "vertical"
Const HorizontalFolder = "landscape"

'Create needed objects
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")

' Define base folder to start from
strBaseDir = objFSO.GetAbsolutePathName("G:\Images")

' Make sure base folder exists, exit if not
If Not objFSO.FolderExists(strBaseDir) Then 
   Wscript.Echo "Base folder missing: """ & strBaseDir & """."
   Wscript.Quit
End If

' Start the process at the base folder
ProcessFolder objFSO.GetFolder(strBaseDir)

Wscript.Quit


Sub ProcessFolder(objFolder)

   If objFolder.Name <> SquareFolder And objFolder.Name <> VerticalFolder And objFolder.Name <> HorizontalFolder Then

      Set objNameSpace = objShell.NameSpace(objFolder.Path)

      ' Process all "*.jpg" files in base folder
      For Each objFile in objFolder.Files
         If LCase(Right(objFile.Name, 4)) = ".jpg" Then

            ' Get image width and height from file metadata
            Set objFileItem = objNameSpace.ParseName(objFile.Name)
            intWidth = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifWidth))
            intHeight = GetNumber(objNameSpace.GetDetailsOf(objFileItem, ExifHeight))

            ' Determine orientation based on dimensions
            Select Case True
              Case intWidth > intHeight
                 strDestDir = objFolder.Path & "\" & HorizontalFolder & "\"
              Case intWidth < intHeight
                 strDestDir = objFolder.Path & "\" & VerticalFolder & "\"
              Case Else
                 strDestDir = objFolder.Path & "\" & SquareFolder & "\"
            End Select

            ' Copy file to appropriated sorted folder
            ' Wscript.Echo intWidth & "," & intHeight & "," & strDestDir & "," & objFile.Name
            If Not objFSO.FolderExists(strDestDir) Then
               objFSO.CreateFolder(strDestDir)
            End If
            objFile.Move strDestDir

         End If
      Next

      ' Drill down into any subfolders
      For Each objSubFolder in objFolder.Subfolders
         ProcessFolder(objSubFolder)
      Next
   End If

End Sub

Function GetNumber(strInfo)
   ' Extract just the first "word" from the string, and remove first character, and then convert to integer
   GetNumber = 0
   On Error Resume Next
   GetNumber = CInt(Mid(Split(strInfo, " ")(0), 2))
   On Error Goto 0
End Function

Open in new window

~bp
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
VB Script

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.