0

I've read many C# tutorials on using lockbits to manipulate images, but I just don't know how to apply this info into PowerShell.

This is the problem:

$image1's height is 2950 pixels. $image2's height is 50 px taller, 3000 pixels. I need to fit $image2 into $image1 and I can skip $image2's first 49 px lines. So in pseudocode:

 For(y=0... For(x=0.... { image1(x,y) = image2(x,y+50) } ....))

The PowerShell script below works, but does not work very fast:

$rect = new-object Drawing.Rectangle 0, 0, $image1.width, $image1.height
$image1drawing.drawimage($image2, 
                         $rect, 
                         0, 50, $image2.width, ($image2.height - 50), 
                         $graphicalUnit)

The pages I've found, such as this (Not able to successfully use lockbits) or this (https://web.archive.org/web/20121203144033/http://www.bobpowell.net/lockingbits.htm) are in "plain English" but how to convert this concept into PowerShell?

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
Lunar Remedy
  • 37
  • 2
  • 9

1 Answers1

1

You are using the correct approach. Using DrawImage will be faster that copying the pixels one by one. Some suggestions to make it faster:

  1. Try using Image.Clone to copy a rectangle from the original image, this will result in the smallest number of objects you need to create.
  2. Make sure you use the same PixelFormat as the original image (faster copying). There is a PixelFormat attribute in Image.
  3. Most important: accessing Width and Height takes a long time so save them to a local variable for reuse. If you know them before hand that's a good way to speed-up things.
  4. Don't expect miracles at a width to height ratio of 4:3 each image is 3932 * 2950 * 3(assuming 24 bit RGB) = 33Mb per image. That's a lot of data, you may easily be be trying to copy a few gigs depending on how many images you have.

You are better off writing a simple cmdlet and using it in your PowerShell script.

BTW in case you are still interested:

Using lockbits in C# (as per your examples) relies on unsafe context and using pointers. I don't believe PowerShell has access to unsafe context.
You can manipulate unmanaged data without using an unsafe context by using the Marshall class; specifically the Read and Write methods (and you might be able to speed things up with the Copy method at expense of memory).
PowerShell was not meant as a replacement for .Net generic languages, that's what CmdLets are for.

Eli Algranti
  • 8,707
  • 2
  • 42
  • 50
  • 1
    Good tips, thank you. You motivated me into doing some more tweaking first and re-checking my loops, variable usage and such. While browsing topics of "set-put-pixel / drawimage/ performance" I mistook lockbits as the universal solution to all programming/graphic problems. – Lunar Remedy Nov 05 '14 at 11:15
  • `LockBits` does not require unsafe operations if you use `Marshal.Copy` to get the bytes out. – Nyerguds Apr 14 '20 at 17:44
  • 1
    @Nyerguds yes you are correct, thanks for pointing that out. It is the C# examples linked by the original poster that used unsafe context not lockbits. The next paragraph mentions the Marshall class as a work around but I was probably not clear enough: You can either use Marshall.Read/Marshall.Write to access the locked bits directly or Marshall.Copy to copy the locked bits to managed memory, manipulate them and copy them back again. In any case writing a cmdlet instead of using a Powershell script is probably the best approach. – Eli Algranti Apr 15 '20 at 06:39