Hi Gdip experts,
I'm wondering if anyone has attempted to split a single image into multiple images with Gdip. The purpose is to place multiple photos on a flatbed scanner, perform a scan to a single, 24-bit color image (probably JPG, but would be fine with a different image format), then run an AHK script that calls Gdip to split the single image into multiple images, one for each photo. The photos will be placed on the flatbed with ample separation so that there is plenty of "white space" to look for when attempting to perform the split.
The goal is to do something similar to Fred Weinhaus' ImageMagick multicrop script (and his updated multicrop2 script), but in AHK, utilizing Gdip. I don't need all the options that Fred has in his ImageMagick scripts — just the primary capability to do the split will be fine.
I'd appreciate any ideas on how to achieve this, especially existing AHK scripts that may be useful. Thanks very much, Joe
Use Gdip to split a single image into multiple images
- JoeWinograd
- Posts: 2200
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: Use Gdip to split a single image into multiple images
Hi JoeWinograd.
I give this topic a little bump because I wonder:
Did you work on this? What is your apporach?
I wouldn't consider the main problem to be related to gdip, the main problem is finding and implementing a good algorithm. Gdip could be used to retreive the pixel array and saveing to file and such. I don't think gdip has any specific functions for this, but I don't really know much about gdip.
I follow this with interest, but I don't think I will work on it (now).
I give this topic a little bump because I wonder:
Did you work on this? What is your apporach?
I wouldn't consider the main problem to be related to gdip, the main problem is finding and implementing a good algorithm. Gdip could be used to retreive the pixel array and saveing to file and such. I don't think gdip has any specific functions for this, but I don't really know much about gdip.
I follow this with interest, but I don't think I will work on it (now).
- JoeWinograd
- Posts: 2200
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: Use Gdip to split a single image into multiple images
Hi Helgef,
Thanks for your reply. My first approach was to use a RunWait call in an AHK script to Fred's multicrop2 script, but he's geared towards Unix usage, and I wasn't having much luck with it in my AHK/Windows environment, which is why I posted this question — hoping that I could create a Gdip-based solution, since I have many AHK scripts that call Gdip and they all work well. While waiting for responses here, I tried another approach — using GIMP with a Divide Scanned Images filter. This approach is working well and I even published a 5-minute video tutorial about it:
How to divide/split a single image file into multiple image files
I'm pleased with that approach, which has worked fine on everything I've thrown at it, but I would still love to have a "pure" AHK script that does it, i.e., all AHK code with calls to only AHK libraries, such as Gdip. But I haven't figured out yet how to even get that approach off the ground. Regards, Joe
Thanks for your reply. My first approach was to use a RunWait call in an AHK script to Fred's multicrop2 script, but he's geared towards Unix usage, and I wasn't having much luck with it in my AHK/Windows environment, which is why I posted this question — hoping that I could create a Gdip-based solution, since I have many AHK scripts that call Gdip and they all work well. While waiting for responses here, I tried another approach — using GIMP with a Divide Scanned Images filter. This approach is working well and I even published a 5-minute video tutorial about it:
How to divide/split a single image file into multiple image files
I'm pleased with that approach, which has worked fine on everything I've thrown at it, but I would still love to have a "pure" AHK script that does it, i.e., all AHK code with calls to only AHK libraries, such as Gdip. But I haven't figured out yet how to even get that approach off the ground. Regards, Joe
Re: Use Gdip to split a single image into multiple images
Very nice tutorial JoeWinograd, good information.
- JoeWinograd
- Posts: 2200
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: Use Gdip to split a single image into multiple images
Thank you, Helgef, I appreciate the kind words.
Re: Use Gdip to split a single image into multiple images
Will somebody please post some relevant code! Arghhh!
OK, the code below will give a Picasso effect, it takes a printscreen, quarters it, and cycles the quarters round the screen like a merry-go-round.
Nice tutorial video, you could use GetPixel to check for whitespace, just got to see if you can work out a satisfactory algorithm. Start off with something and improve it, trial and error. E.g. check every 50th or 25th pixel to begin with, and narrow down.
Maybe you could get some info from an external command line tool, and pass information to AHK and Gdip functions.
A potential problem could be if the images are at an angle and not orthogonal.
It uses SplashImage which I hope will be kept in AHK v2 because it's so convenient.
OK, the code below will give a Picasso effect, it takes a printscreen, quarters it, and cycles the quarters round the screen like a merry-go-round.
Nice tutorial video, you could use GetPixel to check for whitespace, just got to see if you can work out a satisfactory algorithm. Start off with something and improve it, trial and error. E.g. check every 50th or 25th pixel to begin with, and narrow down.
Maybe you could get some info from an external command line tool, and pass information to AHK and Gdip functions.
A potential problem could be if the images are at an angle and not orthogonal.
It uses SplashImage which I hope will be kept in AHK v2 because it's so convenient.
Code: Select all
q:: ;Picasso effect, take a printscreen, quarter it, and cycle quarters like a merry-go-round
;ControlGet, hCtl, Hwnd, , Edit1, A
;WinGetPos, vPosX, vPosY, vPosW, vPosH, ahk_id %hCtl%
vPosX := 0, vPosY := 0, vPosW := A_ScreenWidth, vPosH := A_ScreenHeight
vList := "X,Y,W,H"
;make each dimension an even number
Loop, Parse, vList, `,
if vPos%A_LoopField% & 1
vPos%A_LoopField%--
vPosX1 := 0, vPosY1 := 0
vPosX2 := vPosW/2, vPosY2 := 0
vPosX3 := vPosW/2, vPosY3 := vPosH/2
vPosX4 := 0, vPosY4 := vPosH/2
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen(vPosX "|" vPosY "|" vPosW "|" vPosH)
pBitmapNew := Gdip_CreateBitmap(vPosW, vPosH)
G := Gdip_GraphicsFromImage(pBitmapNew)
Loop, 12
{
vOffset := A_Index-1
Loop, 4
{
;1->2, 2->3, 3->4, 4->1 ;vIndex := Mod(A_Index,4)+1
;note: Gdip_DrawImage, destination coordinates, then source coordinates
vIndex := Mod(A_Index+vOffset,4)+1
Gdip_DrawImage(G, pBitmap, vPosX%vIndex%, vPosY%vIndex%, vPosW/2, vPosH/2, vPosX%A_Index%, vPosY%A_Index%, vPosW/2, vPosH/2)
}
;vPath = %A_Desktop%\z temp %A_Now%.png
;Gdip_SaveBitmapToFile(pBitmapNew, vPath)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmapNew)
SplashImage, HBITMAP:%hBitmap%, B
Sleep 300
}
SplashImage, Off
Gdip_DisposeImage(pBitmap)
Gdip_DeleteGraphics(G)
Gdip_DisposeImage(pBitmapNew)
Gdip_Shutdown(pToken)
MsgBox % "done"
Return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Re: Use Gdip to split a single image into multiple images
That is interesting jeeswgjeeswg wrote:Will somebody please post some relevant code! Arghhh!
- JoeWinograd
- Posts: 2200
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: Use Gdip to split a single image into multiple images
Hi jeeswg,
I could utilize it to check for white space.
Thanks for your interest in this and your ideas! Regards, Joe
Very nice!it takes a printscreen, quarters it, and cycles the quarters round the screen like a merry-go-round
Here's some test code that I played with a while ago to display the RGB of the current mouse position in both decimal and hex:use GetPixel to check for whitespace
Code: Select all
; get color at mouse pos
!^F6:: ; pick whatever hotkey you want
CoordMode,Mouse,Screen
CoordMode,Pixel,Screen
MouseGetPos,Xpos,Ypos
PixelGetColor,HexColor,%Xpos%,%Ypos%,Slow RGB
If (ErrorLevel<>0)
{
MsgBox,4112,Fatal Error,Error Level from PixelGetColor: %ErrorLevel%`nx%Xpos%/y%Ypos%
ExitApp
}
RedDec:=(16*Hex2Dec(SubStr(HexColor,3,1)))+Hex2Dec(SubStr(HexColor,4,1))
GreenDec:=(16*Hex2Dec(SubStr(HexColor,5,1)))+Hex2Dec(SubStr(HexColor,6,1))
BlueDec:=(16*Hex2Dec(SubStr(HexColor,7,1)))+Hex2Dec(SubStr(HexColor,8,1))
MsgBox,4096,x%Xpos%/y%Ypos%,HexRGB=%HexColor%`nDecimalRGB=%RedDec% %GreenDec% %BlueDec%
Return
Hex2Dec(hex)
{
If hex is digit
{
If (hex>9 or hex="")
{
MsgBox,4112,Fatal Error,Bad input sent to Hex2Dec: %hex%
ExitApp
}
Return hex
}
If (hex="a")
Return 10
If (hex="b")
Return 11
If (hex="c")
Return 12
If (hex="d")
Return 13
If (hex="e")
Return 14
If (hex="f")
Return 15
MsgBox,4112,Fatal Error,Non-hex character sent to Hex2Dec: %hex%
ExitApp
}
If I can't do it with all AHK code and libraries, that's definitely a way to go.Maybe you could get some info from an external command line tool, and pass information to AHK and Gdip functions.
Yes, that's why the GIMP-based script can optionally run a GIMP-based plugin called deskew.exe (although my experience with it is that it doesn't work very well).A potential problem could be if the images are at an angle and not orthogonal.
Thanks for your interest in this and your ideas! Regards, Joe
Re: Use Gdip to split a single image into multiple images
I don't do that much with images. An algorithm I might use, that just occurred to me, subject to speed:
Using Gdip_GetPixel (sorry, I meant this, not AHK's PixelGetColor), check every 10th horizontal/vertical pixel's colour. If you find 16 white pixels like so:
. . . .
. . . .
. . . .
. . . .
and all the pixels in all 9 squares are white, then we decide that the central square will not appear in any of the final images. Some of those surrounding squares may be also end up as central squares and discarded. We might refine and discard some further pixels, and leave some bordering whitespace around each image as in your video.
Obviously there is a danger if the image itself contains white pixels.
To test that algorithm you could make all of those central squares red, and view the resulting image.
Then you have to decide which lines to cut. And my script from earlier can cut up images.
Interesting re. deskew.exe.
Yeah I like to do everything by AHK, but then again do I want to recreate SoX and FFmpeg! Although I've found Gdip can do everything I want to do with images ultimately. [EDIT: Actually if I ever find out how these codecs work, I'll probably be wanting to amend them in some way as well.]
Btw did you win some Experts Exchange award or something. I came across an article the other day, I thought the name looked familiar!
Re. dec and hex:
Using Gdip_GetPixel (sorry, I meant this, not AHK's PixelGetColor), check every 10th horizontal/vertical pixel's colour. If you find 16 white pixels like so:
. . . .
. . . .
. . . .
. . . .
and all the pixels in all 9 squares are white, then we decide that the central square will not appear in any of the final images. Some of those surrounding squares may be also end up as central squares and discarded. We might refine and discard some further pixels, and leave some bordering whitespace around each image as in your video.
Obviously there is a danger if the image itself contains white pixels.
To test that algorithm you could make all of those central squares red, and view the resulting image.
Then you have to decide which lines to cut. And my script from earlier can cut up images.
Interesting re. deskew.exe.
Yeah I like to do everything by AHK, but then again do I want to recreate SoX and FFmpeg! Although I've found Gdip can do everything I want to do with images ultimately. [EDIT: Actually if I ever find out how these codecs work, I'll probably be wanting to amend them in some way as well.]
Btw did you win some Experts Exchange award or something. I came across an article the other day, I thought the name looked familiar!
Re. dec and hex:
Code: Select all
q:: ;dec and hex
;for hex2dec:
vNum := 0xFFFFFF
MsgBox % vNum+0 ;16777215
;for dec2hex
vNum := 16777215
MsgBox % Format("0x{:X}", vNum) ;0xFFFFFF
;for splitting hex
vText := 0x0A0B0C
vNum1 := Format("{:d}", "0x" SubStr(vText, 3, 2))
vNum2 := Format("{:d}", "0x" SubStr(vText, 5, 2))
vNum3 := Format("{:d}", "0x" SubStr(vText, 7, 2))
MsgBox % vNum1 " " vNum2 " " vNum3 ;10 11 12
Return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Re: Use Gdip to split a single image into multiple images
A vertical/horizontal conveyor belt (filmstrip) script, similar to the 4 quarters one above.
Code: Select all
q:: ;vertical/horizontal conveyor belt (filmstrip)
vPosX := 0, vPosY := 0, vPosW := A_ScreenWidth, vPosH := A_ScreenHeight
;number of strips
vNum := 8
;strips
vType := "h" ;horizontal
vType := "v" ;vertical
;make each dimension a multiple of n
vPosW := vPosW - Mod(vPosW, vNum)
vPosH := vPosH - Mod(vPosH, vNum)
vStripW := Round(vPosW / vNum)
vStripH := Round(vPosH / vNum)
Loop, % vNum
vPosX%A_Index% := 0, vPosY%A_Index% := (vPosH/vNum) * (A_Index-1)
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen(vPosX "|" vPosY "|" vPosW "|" vPosH)
pBitmapNew := Gdip_CreateBitmap(vPosW, vPosH)
G := Gdip_GraphicsFromImage(pBitmapNew)
Loop, % vNum * 3
{
;vOffset := A_Index-1 ;upwards/leftwards
vOffset := (vNum*A_Index)+1-A_Index ;downwards/rightwards ;keep it positive because of Mod
Loop, % vNum
{
vIndex1 := Mod(A_Index+vOffset,vNum)+1
vIndex2 := Mod(A_Index,vNum)+1
vPosX1 := vStripW*(vIndex1-1)
vPosX2 := vStripW*(vIndex2-1)
vPosY1 := vStripH*(vIndex1-1)
vPosY2 := vStripH*(vIndex2-1)
if (vType = "h")
vPosX1 := 0, vPosX2 := 0, vStripW := vPosW
if (vType = "v")
vPosY1 := 0, vPosY2 := 0, vStripH := vPosH
;note: Gdip_DrawImage, destination coordinates, then source coordinates
Gdip_DrawImage(G, pBitmap, vPosX2, vPosY2, vStripW, vStripH, vPosX1, vPosY1, vStripW, vStripH)
}
;vPath = %A_Desktop%\z temp %A_Now%.png
;Gdip_SaveBitmapToFile(pBitmapNew, vPath)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmapNew)
SplashImage, HBITMAP:%hBitmap%, B
Sleep 300
}
SplashImage, Off
Gdip_DisposeImage(pBitmap)
Gdip_DeleteGraphics(G)
Gdip_DisposeImage(pBitmapNew)
Gdip_Shutdown(pToken)
MsgBox % "done"
Return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Re: Use Gdip to split a single image into multiple images
I was just sitting down, AFK, not thinking about AutoHotkey, and suddenly a basic simpler algorithm occurred to me, namely group together non-whitespace pixels, rather than whitespace pixels.
First determine the criteria for pixels that are whitespace.
- Choose ranges for R, G, B, replace such pixels with red.
- Does that red area correspond to what you consider whitespace?
- Tweak until it's satisfactory.
Imagine dots like so in a grid pattern: '::', all over the image.
- Any such dots that are non-whitespace, and the pixels in the square around them, will end up in one of our final images.
- The size of such squares might be for example, the maximum desired amount of border whitespace around each image.
- Check for adjacent (and nearby) non-whitespace dots, and build up imaginary 'blobs' of nearby squares, ultimately make these into rectangles.
- (If you scanned in a circular coin for example, or an L-shape, the rules would still give you a rectangle.)
- Also extend the edges of those rectangles, based on how much border whitespace you want.
- Those rectangles will then be cut as images.
First determine the criteria for pixels that are whitespace.
- Choose ranges for R, G, B, replace such pixels with red.
- Does that red area correspond to what you consider whitespace?
- Tweak until it's satisfactory.
Imagine dots like so in a grid pattern: '::', all over the image.
- Any such dots that are non-whitespace, and the pixels in the square around them, will end up in one of our final images.
- The size of such squares might be for example, the maximum desired amount of border whitespace around each image.
- Check for adjacent (and nearby) non-whitespace dots, and build up imaginary 'blobs' of nearby squares, ultimately make these into rectangles.
- (If you scanned in a circular coin for example, or an L-shape, the rules would still give you a rectangle.)
- Also extend the edges of those rectangles, based on how much border whitespace you want.
- Those rectangles will then be cut as images.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
- JoeWinograd
- Posts: 2200
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: Use Gdip to split a single image into multiple images
Thank you, jeeswg, for so many interesting ideas. I'll study them over the coming days. Your filmstrip script, like the Picasso one, is cool! Thanks, too, for the dec/hex code.
Yes, that's me. I participate a lot at Experts Exchange and they gave me their annual Most Valuable Expert (MVE) Award, both last year and this year. The article you saw was probably their blog entry announcing this year's awards. Thanks for noticing!Btw did you win some Experts Exchange award or something. I came across an article the other day, I thought the name looked familiar!
Re: Use Gdip to split a single image into multiple images
One thing relevant to the initial problem is trimming whitespace from an image, here's an example:
Code: Select all
;[Gdip functions]
;GDI+ standard library 1.45 by tic - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=6517
q:: ;image on the clipboard - crop whitespace
pToken := Gdip_Startup()
pBitmap := Gdip_CreateBitmapFromClipboard()
Gdip_GetDimensions(pBitmap, vImgW, vImgH)
vCol2 := 0xFFFFFF ;whitespace colour, which colour is 'white'
Loop, 4
{
vIndex := A_Index
if (vIndex = 1) ;get first non-blank row ;y
vRowOrCol := vImgH, vPixel := vImgW, vDiff := 1, vNumRC := -1
else if (vIndex = 2) ;get last non-blank row ;y
vRowOrCol := vImgH, vPixel := vImgW, vDiff := -1, vNumRC := vImgH
else if (vIndex = 3) ;get first non-blank column ;x
vPixel := vImgH, vRowOrCol := vImgW, vDiff := 1, vNumRC := -1
else if (vIndex = 4) ;get last non-blank column ;x
vPixel := vImgH, vRowOrCol := vImgW, vDiff := -1, vNumRC := vImgW
vIsCol := 0
Loop, % vRowOrCol
{
vNumRC += vDiff
Loop, % vPixel
{
vNumP := A_Index-1
if (vIndex = 1) || (vIndex = 2)
vCol := Gdip_GetPixel(pBitmap, vNumP, vNumRC)
else if (vIndex = 3) || (vIndex = 4)
vCol := Gdip_GetPixel(pBitmap, vNumRC, vNumP)
if !((vCol & 0xFFFFFF) = vCol2)
{
vIsCol := 1
break
}
}
if vIsCol
break
if (A_Index = vImgH)
{
MsgBox, % "entire image is one colour"
return
}
}
vPos%vIndex% := vNumRC
}
pBitmap2 := Gdip_CloneBitmapArea(pBitmap, vPos3, vPos1, vPos4-vPos3+1, vPos2-vPos1+1)
Gdip_SetBitmapToClipboard(pBitmap2)
Gdip_DisposeImage(pBitmap)
Gdip_DisposeImage(pBitmap2)
Gdip_Shutdown(pToken)
MsgBox, % "done"
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Re: Use Gdip to split a single image into multiple images
I've created a more versatile script cf. the moving tiles scripts above, this one can do vertical/horizontal movement if you adjust the settings, but it's initially set to do diagonal movement:
Code: Select all
;[Gdip functions]
;GDI+ standard library 1.45 by tic - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=6517
q:: ;gdip diagonal shift (split screen into rectangles, move down and right each time)
vPosX := 0, vPosY := 0, vPosW := A_ScreenWidth, vPosH := A_ScreenHeight
vCountW := 3, vCountH := 4, vNum := 1
vCountW := 3, vCountH := 3, vNum := 3
vCountW := 6, vCountH := 6, vNum := 1
;vCountW := 12, vCountH := 12, vNum := 1
;vCountW := 24, vCountH := 24, vNum := 1
vAdjustW := 1, vAdjustH := 1
;vAdjustW := 1, vAdjustH := -1
;vAdjustW := -1, vAdjustH := 1
;vAdjustW := -1, vAdjustH := -1
;vAdjustW := 1, vAdjustH := 0
;vAdjustW := -1, vAdjustH := 0
;vAdjustW := 0, vAdjustH := 1
;vAdjustW := 0, vAdjustH := -1
;make each dimension a multiple of n
vPosW := vPosW - Mod(vPosW, vCountW)
vPosH := vPosH - Mod(vPosH, vCountH)
vStripW := Round(vPosW / vCountW)
vStripH := Round(vPosH / vCountH)
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen(vPosX "|" vPosY "|" vPosW "|" vPosH)
pBitmapNew := Gdip_CreateBitmap(vPosW, vPosH)
G := Gdip_GraphicsFromImage(pBitmapNew)
vNow := A_Now
vOffsetW := 0
vOffsetH := 0
Loop, % vNum * ((vCountW=vCountH) ? vCountW : (vCountW*vCountH))
{
vOffsetW += vAdjustW
vOffsetH += vAdjustH
Loop, % vCountH
{
vIndexY1 := A_Index-1
vIndexY2 := Mod(A_Index-1+vOffsetH, vCountH)
if (vIndexY2 < 0)
vIndexY2 += vCountH
Loop, % vCountW
{
vIndexX1 := A_Index-1
vIndexX2 := Mod(A_Index-1+vOffsetW, vCountW)
if (vIndexX2 < 0)
vIndexX2 += vCountW
vPosX1 := vStripW*(vIndexX1)
vPosY1 := vStripH*(vIndexY1)
vPosX2 := vStripW*(vIndexX2)
vPosY2 := vStripH*(vIndexY2)
;note: Gdip_DrawImage, destination coordinates, then source coordinates
Gdip_DrawImage(G, pBitmap, vPosX2, vPosY2, vStripW, vStripH, vPosX1, vPosY1, vStripW, vStripH)
}
}
;vIndex := Format("{:04}", A_Index)
;vPath = %A_Desktop%\z temp %vNow% %A_Index%.png
;Gdip_SaveBitmapToFile(pBitmapNew, vPath)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmapNew)
SplashImage, % "HBITMAP:" hBitmap, B
Sleep, 300
}
SplashImage, Off
Gdip_DisposeImage(pBitmap)
Gdip_DeleteGraphics(G)
Gdip_DisposeImage(pBitmapNew)
Gdip_Shutdown(pToken)
MsgBox, % "done"
return
;==================================================
;e.g. shift down + right
;ABC
;DEF
;HIJ
;JHI
;CAB
;FDE
;EFD
;IJH
;BCA
;ABC
;DEF
;HIJ
;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Re: Use Gdip to split a single image into multiple images
I have a working script for the original problem:
Code: Select all
;split a single image into multiple images introduction
;links:
;Gdip: image binary data to hex string for OCR - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=35339
;check if rectangles (windows) overlap - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=30809
;convert pixels to text (pixels to RGB hex)
;check each pixel:
;if pixel is a background colour, continue
;if pixel is not a background colour,
;... check against existing rectangles:
;- if it matches 2 or more rectangles, combine those rectangles, expand rectangle if necessary
;- if it matches 1 rectangle, expand rectangle if necessary
;- else, create new rectangle
;to finish:
;compare rectangles, combine any that overlap
;creating/expanding rectangles works like this:
;if border distance is 2:
;point (10,10) will have rectangle (8,8) to (12,12)
;if border distance is 0:
;point (10,10) will have rectangle (10,10) to (10,10)
;==================================================
;[Gdip functions]
;GDI+ standard library 1.45 by tic - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=6517
q:: ;split a single image into multiple images
pToken := Gdip_Startup()
vPath = %A_Desktop%\MyFile.png
vDirOut = %A_Desktop%
pBitmap := Gdip_CreateBitmapFromFile(vPath)
Gdip_GetImageDimensions(pBitmap, vImgW, vImgH)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
VarSetCapacity(DIBSECTION, vSizeDS:=A_PtrSize=8?104:84, 0)
DllCall("gdi32\GetObject", Ptr,hBitmap, Int,vSizeDS, Ptr,&DIBSECTION)
vAddr := NumGet(&DIBSECTION, A_PtrSize=8?24:20, "Ptr") ;bmBits
vSize := NumGet(&DIBSECTION, A_PtrSize=8?52:44, "UInt") ;biSizeImage
vHex := JEE_BinDataToHex(vAddr, vSize)
vOutput := RegExReplace(vHex, "(.{6})(.{2})", ",$1")
vOutput := RegExReplace(vOutput, ".{" (7*vImgW) "}", "$0`n")
;note: image hex data is upside down (top row of pixels are at bottom of string)
vOutput := JEE_StrReverseLines(vOutput, "`n", "")
vOutput := SubStr(vOutput, 2)
vBdrL := 2, vBdrR := 2
vBdrT := 2, vBdrB := 2
vX := -1, vY := 0
oRect := {}
Loop, Parse, vOutput, % ","
{
vX += 1
if (vX = vImgW)
vX := 0, vY += 1
vTemp := A_LoopField
if (vTemp = "FFFFFF")
continue
oTemp := [vX-vBdrL, vY-vBdrT, vX+vBdrR, vY+vBdrB]
;MsgBox, % Format("{}, {}, {}, {}", oTemp*)
vLastMatch := 0
Loop, % oRect.Length()
{
vIndex := oRect.Length() + 1 - A_Index
if !JEE_RectObjOverlap(oTemp, oRect[vIndex])
continue
oRect[vIndex] := JEE_RectObjCombine(oTemp, oRect[vIndex])
if vLastMatch
{
oRect[vIndex] := JEE_RectObjCombine(oRect[vIndex], oRect[vLastMatch])
oRect.RemoveAt(vLastMatch)
}
vLastMatch := vIndex
}
if !vLastMatch
oRect.Push(oTemp)
}
;MsgBox, % oRect.Length()
;safety check
;compare rectangles, combine any that overlap
Loop, % oRect.Length()
{
vIndex2 := oRect.Length() + 1 - A_Index
oTemp := oRect[vIndex2]
vLastMatch := 0
Loop, % oRect.Length()
{
vIndex := oRect.Length() + 1 - A_Index
if (vIndex >= vIndex2)
continue
if !JEE_RectObjOverlap(oTemp, oRect[vIndex])
continue
oRect[vIndex] := JEE_RectObjCombine(oTemp, oRect[vIndex])
if vLastMatch
{
oRect[vIndex] := JEE_RectObjCombine(oRect[vIndex], oRect[vLastMatch])
oRect.RemoveAt(vLastMatch)
}
vLastMatch := vIndex
}
}
;MsgBox, % oRect.Length()
;rectangles to images
vNow := A_Now
Loop, % oRect.Length()
{
;MsgBox, % Format("{} {} {} {}", oRect[A_Index]*)
vPosX := oRect[A_Index].1
vPosY := oRect[A_Index].2
vPosW := oRect[A_Index].3 - oRect[A_Index].1 + 1
vPosH := oRect[A_Index].4 - oRect[A_Index].2 + 1
pBitmapNew := Gdip_CreateBitmap(vPosW, vPosH)
G := Gdip_GraphicsFromImage(pBitmapNew)
;note: Gdip_DrawImage, destination coordinates, then source coordinates
Gdip_DrawImage(G, pBitmap, 0, 0, vPosW, vPosH, vPosX, vPosY, vPosW, vPosH)
hBitmapNew := Gdip_CreateHBITMAPFromBitmap(pBitmapNew)
SplashImage, % "HBITMAP:" hBitmapNew, B
Sleep, 2000
SplashImage, Off
vIndex := Format("{:04}", A_Index)
vPath = %vDirOut%\z split image %vNow% %vIndex%.png
if !FileExist(vPath)
Gdip_SaveBitmapToFile(pBitmapNew, vPath)
DeleteObject(hBitmapNew)
Gdip_DisposeImage(pBitmapNew)
}
DeleteObject(hBitmap)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
MsgBox, % "done"
return
;==================================================
JEE_BinDataToHex(vAddr, vSize)
{
;CRYPT_STRING_HEX := 0x4 ;to return space/CRLF-separated text
;CRYPT_STRING_HEXRAW := 0xC ;to return raw hex (not supported by Windows XP)
DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4, Ptr,0, UIntP,vChars)
VarSetCapacity(vHex, vChars*2, 0)
DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4, Str,vHex, UIntP,vChars)
vHex := StrReplace(vHex, "`r`n")
vHex := StrReplace(vHex, " ")
return vHex
}
;==================================================
JEE_StrReverseLines(ByRef vText, vDelim:="`r`n", vSep:="`r`n")
{
if (vText = "")
return vText
vOutput := ""
VarSetCapacity(vOutput, StrLen(vText)*2)
oArray := StrSplit(vText, vDelim)
Loop, % oArray.Length() - 1
vOutput .= oArray[oArray.Length()+1-A_Index] vSep
vOutput .= oArray.1
return vOutput
}
;==================================================
JEE_RectObjCombine(oRect1, oRect2)
{
oRect := []
oRect.1 := oRect1.1 < oRect2.1 ? oRect1.1 : oRect2.1 ;min
oRect.2 := oRect1.2 < oRect2.2 ? oRect1.2 : oRect2.2 ;min
oRect.3 := oRect1.3 > oRect2.3 ? oRect1.3 : oRect2.3 ;max
oRect.4 := oRect1.4 > oRect2.4 ? oRect1.4 : oRect2.4 ;max
return oRect
}
;==================================================
JEE_RectObjOverlap(oRect1, oRect2)
{
;if (A is left of B) [rightmost A is left of leftmost B]
;|| (A is right of B) [leftmost A is right of righttmost B]
;|| (A is is above B) [bottom of A is is above top of B]
;|| (A is is below B) [top of A is is below bottom of B]
;then A and B do not overlap
if (oRect1.3 < oRect2.1)
|| (oRect1.1 > oRect2.3)
|| (oRect1.4 < oRect2.2)
|| (oRect1.2 > oRect2.4)
return 0
else
return 1
}
;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Re: Use Gdip to split a single image into multiple images
Pass the original pBitmap to this function with the x,y,w,h you want from it and it will return pBitmap2 you can save.
If the images are precisely put on the scanner the same way every time then this could work without repeat checking of the positions.
HTH
Note:
To put them on the scanner in the same positions every time i would make a template fixture with rectangle holes the images fit into.
This way you can scan them precisely as fast as possible.
edit: added additional note.
If the images are precisely put on the scanner the same way every time then this could work without repeat checking of the positions.
Code: Select all
Gdip_CropImage(pBitmap, x, y, w, h)
{
pBitmap2 := Gdip_CreateBitmap(w, h), G2 := Gdip_GraphicsFromImage(pBitmap2)
Gdip_DrawImage(G2, pBitmap, 0, 0, w, h, x, y, w, h)
Gdip_DeleteGraphics(G2)
return pBitmap2
}
Note:
To put them on the scanner in the same positions every time i would make a template fixture with rectangle holes the images fit into.
This way you can scan them precisely as fast as possible.
edit: added additional note.
Re: Use Gdip to split a single image into multiple images
@Xtra: It's possible that the Gdip_CloneBitmapArea function already does this, with similar or exactly the same results.
I was considering replacing Gdip_DrawImage with Gdip_CloneBitmapArea, I'm not sure if one is preferable to the other.
One thing that has to be considered is how functions handle transparency.
I was considering replacing Gdip_DrawImage with Gdip_CloneBitmapArea, I'm not sure if one is preferable to the other.
One thing that has to be considered is how functions handle transparency.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Re: Use Gdip to split a single image into multiple images
@jeeswg Gdip_CloneBitmapArea looks like a better option its worth checking out. I will check it out when i get time.
Note:
@jeeswg Gdip_CloneBitmapArea works great for this and by default the image format is PixelFormat32bppARGB so transparency is not an issue.
Here is a list of all the image formats: Names, Dec, Hex and Description
edit: add note
Note:
@jeeswg Gdip_CloneBitmapArea works great for this and by default the image format is PixelFormat32bppARGB so transparency is not an issue.
Here is a list of all the image formats: Names, Dec, Hex and Description
Spoiler
edit: add note
- JoeWinograd
- Posts: 2200
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: Use Gdip to split a single image into multiple images
Hi jeeswg,
A huge thanks for those two scripts! I tested both — they both work perfectly! I wrote a script for a client that needs to trim the whitespace on every page of a multi-page PDF. My script calls Xpdf's PDFtoPNG.exe utility to convert each page to a PNG, and then calls ImageMagick's magick.exe to trim the whitespace. Your code provides an alternative to ImageMagick for trimming the whitespace. Likewise, your script to split a single image into multiple images gives me a lot more flexibility than I have with the GIMP and Divide-Scanned-Images filter that I've been using. I can see incorporating it into an AHK script that processes all images in a folder, even recursing into subfolders. It can be compiled into a stand-alone program so the user won't have to download/install GIMP, the Divide-Scanned-Images filter, or, for that matter, anything. I very much appreciate your efforts!
Hi Xtra,
Thanks for your efforts to tweak jeeswg's code — much appreciated!
Regards, Joe
A huge thanks for those two scripts! I tested both — they both work perfectly! I wrote a script for a client that needs to trim the whitespace on every page of a multi-page PDF. My script calls Xpdf's PDFtoPNG.exe utility to convert each page to a PNG, and then calls ImageMagick's magick.exe to trim the whitespace. Your code provides an alternative to ImageMagick for trimming the whitespace. Likewise, your script to split a single image into multiple images gives me a lot more flexibility than I have with the GIMP and Divide-Scanned-Images filter that I've been using. I can see incorporating it into an AHK script that processes all images in a folder, even recursing into subfolders. It can be compiled into a stand-alone program so the user won't have to download/install GIMP, the Divide-Scanned-Images filter, or, for that matter, anything. I very much appreciate your efforts!
Hi Xtra,
Thanks for your efforts to tweak jeeswg's code — much appreciated!
Regards, Joe
Re: Use Gdip to split a single image into multiple images
Cool jeeswg, thanks for sharing
Who is online
Users browsing this forum: Google [Bot], Joey5 and 304 guests