Batch Process JPEG files

Started by nrr, October 14, 2021, 06:21:04 AM

Previous topic - Next topic

nrr

I have a few hundred jpg files in a folder that I want to read, modify, and save.  The modification is to apply a few straight lines to each photo.  I know the start and end points for each line.  Can I do this with Winbatch or can anyone suggest an alternative to batch process multiple jpg photos.  (I know how to loop through the folder and read/write each file but how can I write the lines on each photo?)
Thanks.

kdmoyers

One random thought that pops into mind: are all the photos the same dimensions? so that the lines would fall in exactly the same spots?
If so, then maybe the lines could be rendered out in a transparent overlay layer.  You would retrieve each photo, overlay the layer, save it back.

ImageMagick does these kind of operations very well, and there are examples of using winbatch to automate ImageMagick
https://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsrch.web+~+TechHome

However, ImageMagick is... a lot.  Much tinkering will be required.
The mind is everything; What you think, you become.

JTaylor

Hmmmmmmmm.....Trying to think if the Omnibus Extender can do that???


Jim

JTaylor

Currently it probably won't do what you need.   It allows you to place text but I don't think you could get a solid line.   I can look at adding that option though.   As Kirby noted, ImageMagik could probably do what you need but can sometimes be a bit of a challenge.

Jim

td

There is always the "System.Drawing" (https://docs.microsoft.com/en-us/dotnet/api/system.drawing?view=netframework-4.8) .Net namespace. It is a bit of a challenge to use and the WinBatch based examples using the namespaces' classes are limited in the Tech Database. One approach would be to convert the jpeg to a bitmap and then use the "System.Drawing" classes to modify the bitmap and then convert it back to the jpeg format. The "System.Drawing" classes are basically a .Net cover for the GDI+ Win32 functions. It would be even more of a challenge to use the GDI+ Win32 functions directly in a series of WinBatch DllCall function calls.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

I added an imDrawLine() function to the wbOmnibus Extender.   If you need straight lines it should do the job.

   http://www.jtdata.com/anonymous/wbOmnibus.zip

Jim

nrr

Jim,

I downloaded the Omnibus extender and it is exactly what I need!!.  Thanks so much.

Kirby and Tony .... thank you both for your suggestions as well.  I did start to look into ImageMagick but as noted, it is a little much.

Nick

td

The OP has a solution but here is another approach using dotNet. It is definitely a bit over the top. The script represents a quick cut&paste of snippets from several scripts sitting in a folder on my workstation. Mostly created it just to satisfy curiosity so take it for what it is worth. One other issue is that the output doubles the DPI of the input even though it is in jpeg format. Alternatively, the task could likely be accomplished using the dotNet "Graphics" class with a single call to the "System.Drawing.Graphics" class's "DrawLine" method.

Code (winbatch) Select
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;  CompileWbColor
;;
;;  Performs an in-memory compilation of a System.Drawing.Color helper class.  This class
;;  is necessary because the CLR does not allow WIL CLR hosting to access the methods of
;;  the class as it is always returned as an unsigned integer strip of its object identity.
;;
;; returns 1 on succes; otherwise: aborts script on compiler errors.
;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#definefunction CompileWbColor ()
   objCSharp = ObjectClrNew('Microsoft.CSharp.CSharpCodeProvider')
   objParams = ObjectClrNew('System.CodeDom.Compiler.CompilerParameters')
   objParams.ReferencedAssemblies.Add("System.Drawing.dll")
   objParams.GenerateInMemory = ObjectType( "VT_BOOL", 1 )
   cSharpSource = $"
using  System.Drawing;
namespace WinBatch {
   public class WbColor  {
     
      public void SetColor (Bitmap objBitMap, int x, int y, int nColor)
      {
         // Need to flip the colors because the .Net structure
         // representation is in abgr order which is how the bitmap
         // actually stores color information.
         int a =  (nColor>>24) & 0x000000ff;
         int b = (nColor>>16) & 0x000000ff;
         int g = (nColor>>8) & 0x000000ff;
         int r = nColor & 0x000000ff;
         objBitMap.SetPixel(x, y, Color.FromArgb(a, r, g, b));
      }
   }
}
;$"

   objResult = objCSharp.CompileAssemblyFromSource(objParams,cSharpSource)

   ; Shouldn't see any of this if the C# code is written correctly.
   strOutput = ''
   bError = 0
   If objResult.Output.Count > 0
      strOuput - 'Compiler Output: ':@lf
      For x = 0 To objResult.Output.Count-1
         If strOutput == "" Then strOutput = objResult.Output.Item(x)
         Else strOutput = strOutput:@LF:objResult.Output.Item(x)
      Next
   EndIf
   ; Compiler Errors
   If objResult.Errors.Count > 0
      strErrors = ''
      ForEach ce In objResult.Errors
         If strErrors == "" Then strErrors = ce.ToString()
         Else strErrors = strErrors:@LF:ce.ToString()
       Next
      strOuput := @lf:@lf:'Compiler Errors: ':lf:strErrors
      bError = 1
   EndIf
   if strOutput != ''
      Pause('Compile Report', strOutput)
      if bError then exit ; Abort on compiler error.
   endif
 
   ; Releasing objects is not necessary because all valiables
   ; are automaticaly release because the UDFs variable table
   ; is cleared when the variables go out of scope.
   return 1
#endfunction

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Main
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Load assemblies required by the three UDFs.
ObjectClrOption('useany', 'System')
ObjectClrOption('useany', 'System.Drawing')

;; Compile the helper class.
CompileWbColor ()

; Load an jpeg into an image object.
objImage = ObjectClrNew('System.Drawing.Bitmap', "c:\temp\01_20200725144030.jpg")
objWbColor = ObjectClrNew('WinBatch.WbColor') ; Get an instance of the helper class.

; Modify the image by placing a black line in the middle.
nX = objImage.Width()
nY = objImage.Height()
nMid = nY/2
nMax = nX - 1
z = objImage.HorizontalResolution()
for i = 0 to nMax
   ;; 0 means the color black.
   objWbColor.SetColor(objImage, i, nMid, i4:0)
next

; Create a a format object using the jpeg image guild.
; (Not sure if this is necessary but it's here anyway.)
;Guild = ObjectClrNew('System.Guid','b96b3cae-0728-11d3-9d7b-0000f81ef32e')
;objFormat = ObjectClrNew('System.Drawing.Imaging.ImageFormat',Guild )
; Save the jpeg to a different file
;objImage.Save('c:\temp\BlackLined.jpeg',objFormat )

; Save the jpeg to a different file
objImage.Save('c:\temp\BlackLined.jpeg')

objImage.Finalize()
exit
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

I did post an update to make diagonal lines work.   They still come out jagged though but they now work properly.

    http://www.jtdata.com/anonymous/wbOmnibus.zip


Jim