AutoHotkey Community

It is currently May 27th, 2012, 10:09 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: July 13th, 2006, 4:49 am 
Offline

Joined: February 13th, 2006, 10:40 pm
Posts: 389
Location: Utah
Quote:
Foreword

When i was working on including files into an uncompiled script I had this little side project and i am pretty proud of it.

It is a function that can create a bitmap from a list of colors (in BGR) and a specified width and height.


Quote:
Application

Code:
WriteBMP(file     ; the file to save the bitmap to
        ,colors   ; the list of colors IN BGR FORMAT!!! for ex. "102bacf810ace01..."
        ,width    ; width of the bitmap (default = 16)
        ,height   ; height of the bitmap (default = 16)
        ,padded)  ; if the bitmap is padded pass a 1 (if you dont know what that means, pass 0 or leave blank)


It comes in handy for taking snapshots of a portion of the screen, rather than screen printing then editing in paing. Aside from the fact that bitmaps are relatively huge in file size it is really useful.

Code:
WriteBMP(file,colors,width=16,height=16,padded=0)
{
  ;first check if we have the right number of pixels
   if padded = 0
      if strlen(colors)/6 <> height*width
         msgbox,% "Pixel Mismatch detected!`n(The Height*Width you specified does not match the number of pixels you provided, or the padding is incorrect) The BMP will be corrupted.`nWidth:" width " Height:" Height "`nPixels provided:" strlen(colors)/6 " Pixels needed: " width*height
   if padded
      if (strlen(colors)/6 - mod(width,4)*height)<> height*width
         msgbox,% "Pixel Mismatch detected!`n(The Height*Width you specified does not match the number of pixels you provided, or the padding is incorrect) The BMP will be corrupted.`nWidth:" width " Height:" Height "`nPixels provided:" strlen(colors)/6 " Pixels needed: " width*height
  ;if the bitmap is not padded we need to pad it
   if (padded = 0) and (mod(width,4) <> 0) ;our bitmap was not provided with padding and it needs it
   {
      loop, %height%
      {
         stringmid,row,colors,% width * 6 * (A_index-1) + 1,% width*6
         colorspadded := colorspadded row removehex(padhex(0,mod(width,4)))  ;add the needed number of 00 bytes
      }
      colors := colorspadded
   }
  ;now we need to create the actual bitmap, starting with the header
   setformat,integer,H
   width := removehex(padhex(width+0,4))      ;this makes the width and height into "words" or 4 bytes long
   height := removehex(padhex(height+0,4))
   ;          B M size    reserved     offbits bitsize                    planes  bitcount (24 bit), and the rest is color table (0s)
   BMPHex := "424d0000000000000000" . "3600000028000000" . width . height "0100" . "1800" . "000000000000000000000000000000000000000000000000" . colors

  ;Create the file
   Handle :=  DllCall("CreateFile","str",file,"Uint",0x40000000
                  ,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
   Loop
   {
     if strlen(BMPHex) = 0
        break
     StringLeft, Hex, BMPHex, 2         
     StringTrimLeft, BMPHex, BMPHex, 2 
     Hex = 0x%Hex%
     DllCall("WriteFile","UInt", Handle,"UChar *", Hex
     ,"UInt",1,"UInt *",UnusedVariable,"UInt",0)
    }
  ;close the file
   DllCall("CloseHandle", "Uint", Handle)
   return 0
}

padhex(hexin,bytes)                                ;pads a hex number to the specified byte length
{
   if Mod(strlen(hexin),2)                         ;the string is an odd number of digits long
   {
      hexin := removehex(hexin)                    ; remove the "0x" temporarily
      hexin := "0x0" hexin   ;for ex: A into 0x0A  ; now add "0x0"
   }
   loop, % bytes - strlen(hexin)/2 + 1             ;add zeros to the end till we get the desired byte length
      hexin := hexin "00"
   return hexin
}

removehex(hexin)                                   ;removes the 0x from hex
{
   stringleft,beg,hexin,2
   if beg = 0x
      stringtrimleft,hexin,hexin,2
   return hexin
}



Quote:
Example

If you Ctrl-Drag on the screen it takes a snapshot of that section of the screen and saves it to your desktop (i hope). I created this because i was tired of having to printscreen my whole 1600*1200 desktop and then edit the file for a 16*16 picture. Please post feedback!

Code:
#singleinstance force
#noenv

file = C:\Documents and Settings\%A_username%\Desktop\ThisBMPwasmadewithAHK.bmp

~^LButton::
   colorlist =
   CoordMode, Mouse, Screen
   CoordMode, Tooltip, Screen
   CoordMode, Pixel, Screen
   MouseGetPos, start_x, start_y
   ToolTip, ., start_x, start_y
   WinSet, Transparent, 100, ahk_class tooltips_class32
   loop
   {
      MouseGetPos, current_x, current_y
      WinMove, ahk_class tooltips_class32, , , , % current_x - start_x, % current_y - start_y
      GetKeyState, state, LButton
      if state=u
      {
         tooltip
         break
      }
   }
   mousegetpos, end_x, end_y 
   TrayTip, ,Retreiving Colors..., , 1
   width := end_x - start_x
   height := end_y - start_y
   loop, %height%
   {
      pixely := start_y + height - A_index - 1    ;because bitmaps are written backwards
      loop, %width%
      {
         pixelx := start_x + A_index - 1
         pixelgetcolor,color,pixelx,pixely  ;get the BGR value
         color := removehex(color)
         colorlist := colorlist color
      }
   }
   TrayTip, ,Saving Bitmap..., , 1
   WriteBMP(file,colorlist,width,height,0)
   TrayTip, ,Done!, , 1
return

WriteBMP(file,colors,width=16,height=16,padded=0)
{
  ;first check if we have the right number of pixels
   if padded = 0
      if strlen(colors)/6 <> height*width
         msgbox,% "Pixel Mismatch detected!`n(The Height*Width you specified does not match the number of pixels you provided, or the padding is incorrect) The BMP will be corrupted.`nWidth:" width " Height:" Height "`nPixels provided:" strlen(colors)/6 " Pixels needed: " width*height
   if padded
      if (strlen(colors)/6 - mod(width,4)*height)<> height*width
         msgbox,% "Pixel Mismatch detected!`n(The Height*Width you specified does not match the number of pixels you provided, or the padding is incorrect) The BMP will be corrupted.`nWidth:" width " Height:" Height "`nPixels provided:" strlen(colors)/6 " Pixels needed: " width*height
  ;if the bitmap is not padded we need to pad it
   if (padded = 0) and (mod(width,4) <> 0) ;our bitmap was not provided with padding and it needs it
   {
      loop, %height%
      {
         stringmid,row,colors,% width * 6 * (A_index-1) + 1,% width*6
         colorspadded := colorspadded row removehex(padhex(0,mod(width,4)))  ;add the needed number of 00 bytes
      }
      colors := colorspadded
   }
  ;now we need to create the actual bitmap, starting with the header
   setformat,integer,H
   width := removehex(padhex(width+0,4))      ;this makes the width and height into "words" or 4 bytes long
   height := removehex(padhex(height+0,4))
   ;          B M size    reserved     offbits bitsize                    planes  bitcount (24 bit), and the rest is color table (0s)
   BMPHex := "424d0000000000000000" . "3600000028000000" . width . height "0100" . "1800" . "000000000000000000000000000000000000000000000000" . colors

  ;Create the file
   Handle :=  DllCall("CreateFile","str",file,"Uint",0x40000000
                  ,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
   Loop
   {
     if strlen(BMPHex) = 0
        break
     StringLeft, Hex, BMPHex, 2         
     StringTrimLeft, BMPHex, BMPHex, 2 
     Hex = 0x%Hex%
     DllCall("WriteFile","UInt", Handle,"UChar *", Hex
     ,"UInt",1,"UInt *",UnusedVariable,"UInt",0)
    }
  ;close the file
   DllCall("CloseHandle", "Uint", Handle)
   return 0
}

padhex(hexin,bytes)                                ;pads a hex number to the specified byte length
{
   if Mod(strlen(hexin),2)                         ;the string is an odd number of digits long
   {
      hexin := removehex(hexin)                    ; remove the "0x" temporarily
      hexin := "0x0" hexin   ;for ex: A into 0x0A  ; now add "0x0"
   }
   loop, % bytes - strlen(hexin)/2 + 1             ;add zeros to the end till we get the desired byte length
      hexin := hexin "00"
   return hexin
}

removehex(hexin)                                   ;removes the 0x from hex
{
   stringleft,beg,hexin,2
   if beg = 0x
      stringtrimleft,hexin,hexin,2
   return hexin
}


Special thanks to Goyyah for his great idea for organizing a post using qoutes

_________________
Image
"Power can be given overnight, but responsibility must be taught. Long years go into its making."


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 13th, 2006, 6:42 am 
Offline

Joined: June 8th, 2006, 2:41 am
Posts: 285
nice idea, but it’s a little slow.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 13th, 2006, 8:29 am 
Not yet tested :roll: but the concept seems to be perfect to capture a collection of images from the same screen coords (SetTimer) to be compared/used with AHK's ImageSearch ...

Thx for sharing it. 8)


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 13th, 2006, 3:24 pm 
Offline

Joined: February 13th, 2006, 10:40 pm
Posts: 389
Location: Utah
@ d-man

for small captures it is reasonably fast

(times below are based on my 1.0 ghz 392 mb ram laptop)

for a 50 by 50 it takes about 4 seconds, and for a 16 by 16 it takes less than a second. both are much faster than printscreening then editing part of it out.

but for something like a 100 by 100 it can take 20+ seconds. becuase it has to retreive the color of some 10,000 pixels, then write them to a file.

It gets exponentially longer as you take a bigger snapshot, so this is more for taking small snapshots of things rather than large things, for that use Print-Screen (or Alt-Printscreen to capture the active windows)

_________________
Image
"Power can be given overnight, but responsibility must be taught. Long years go into its making."


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Saving to ppm format,
PostPosted: July 17th, 2006, 10:08 am 
Offline

Joined: July 13th, 2006, 7:47 pm
Posts: 4
Nice, this makes me able to drop the need for one external tool in my script for conversion from ppm to bmp.

Also made a similar tool just the other day, but as I needed a image file in the ppm format (bmp returning feed back to the GUI, as ppm is not supported).

The ppm fomat is more simple than bmp (including not upside down), and also in asci, using th following syntax:

Format for PPM image file can be like,

Code:
P3
# example from the man page
4 4
15
 0  0  0    0  0  0    0  0  0   15  0 15
 0  0  0    0 15  7    0  0  0    0  0  0
 0  0  0    0  0  0    0 15  7    0  0  0
15  0 15    0  0  0    0  0  0    0  0  0



A early example is in the post: http://www.autohotkey.com/forum/viewtopic.php?t=2774&postdays=0&postorder=asc&start=15

As it so slow for large grabs, locking of mouse/keyboard may also be useful if not to change the screen while its scanning.

//Regards m2


Last edited by m2 on July 17th, 2006, 4:15 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2006, 1:51 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
WriteBMP() itself is quite fast. This is very useful, thanks!

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2006, 9:08 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
It looks cool, but I got invalid bmp files (size 54 bytes). Do I need to change something in the script? (Also, %A_Desktop% works with other than English Windows, too.)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 18th, 2006, 12:26 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
I think the problem was that my application reacted to Ctrl-Click strangely, and also, the mouse tracking loop consumed too much processor power (we ought to slow it down). Here is a version, which is more stable for my weird editor.
Code:
#SingleInstance force
#NoEnv
Process Priority,,High
SetBatchLines -1

file = %A_Desktop%\AHK-made.bmp
CoordMode, Mouse, Screen
CoordMode, Tooltip, Screen
CoordMode, Pixel, Screen

+^LButton::
   colorlist =
   MouseGetPos, start_x, start_y
   ToolTip, %A_Space%, start_x, start_y
   WinSet, Transparent, 150, ahk_class tooltips_class32
   SetTimer mouse, 50
Return

mouse:
   MouseGetPos, current_x, current_y
   WinMove, ahk_class tooltips_class32, , , , % current_x - start_x, % current_y - start_y
   If GetKeyState("LButton", "P")
      Return
   SetTimer mouse, OFF
   ToolTip
   MouseGetPos, end_x, end_y
   TrayTip, ,Retreiving Colors..., , 1
   width := end_x - start_x
   height := end_y - start_y
   Loop, %height%
   {
      pixely := start_y + height - A_index - 1    ;because bitmaps are written backwards
      loop, %width%
      {
         pixelx := start_x + A_index - 1
         pixelgetcolor,color,pixelx,pixely  ;get the BGR value
         color := removehex(color)
         colorlist := colorlist color
      }
   }
   TrayTip, ,Saving Bitmap..., , 1
   WriteBMP(file,colorlist,width,height,0)
   TrayTip, ,Done!, , 1
Return

;...
I also changed the hotkey to Shift-Ctrl-LButton, because it had no function I would miss.

In any case, this is a useful script, programmed nicely. It helps creating our own icons. Congratulations, and thanks for sharing it!


Report this post
Top
 Profile  
Reply with quote  
PostPosted: August 28th, 2006, 2:13 am 
Offline

Joined: August 20th, 2006, 11:44 pm
Posts: 29
Location: Ottawa
I wanted to try ur code and got an error message, wonder if it was tested or not?

Error: call to nonexistent function

color := removehex(color)

_________________
There is always something new to learn.
_________________
http://autohotkey.net/~Fabiolus/


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Oh I see
PostPosted: August 28th, 2006, 2:20 am 
Offline

Joined: August 20th, 2006, 11:44 pm
Posts: 29
Location: Ottawa
Okay nevermind I got it to work but where does it save the file?

_________________
There is always something new to learn.
_________________
http://autohotkey.net/~Fabiolus/


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Re: Oh I see
PostPosted: August 28th, 2006, 9:18 am 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
Fabiolus wrote:
Okay nevermind I got it to work but where does it save the file?
In the path you give in the file variable.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 28th, 2006, 12:22 pm 
Offline

Joined: July 12th, 2005, 1:21 pm
Posts: 633
I tried the function and got also a corrupt Bitmap with size 24065x4353 which can't be displayed...

Should I send you the file?

Thalon

_________________
AHK-Icon-Changer
AHK-IRC
deutsches Forum


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 29th, 2006, 12:40 am 
Offline

Joined: February 13th, 2006, 10:40 pm
Posts: 389
Location: Utah
lol um, that depends, how big is it? lol
and were you using my function or Laszlos?

_________________
Image
"Power can be given overnight, but responsibility must be taught. Long years go into its making."


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 29th, 2006, 9:36 am 
Offline

Joined: July 12th, 2005, 1:21 pm
Posts: 633
I have used both examples!
Your example:
406.074 Bytes (396kB) and 12033x48641 Pixel

Laszlos:
287.250 Bytes (280kB) and 4353x24065 Pixel

If you are interested in please send me a PM with your E-Mail-Data.

I have used the scripts to make screenshots over an area of maximum 500x800 (little part of my screen :) ).

Thalon

_________________
AHK-Icon-Changer
AHK-IRC
deutsches Forum


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 29th, 2006, 6:17 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
The problem is that the width and height of the selection has to be coded in little endian format in the bmp file. If the picture has less than 256 pixels in either direction, the scripts work. Otherwise, we have to swap the bytes in the padhex function. The simple fix below works up to 64K pixels horizontally or vertically, which should be enough for all monitors.
Code:
SetFormat Integer,H
CoordMode Mouse, Screen
CoordMode Tooltip, Screen
CoordMode Pixel, Screen
file = %A_Desktop%\AHK-made.bmp

+^LButton::                                     ; Shift-Control-Drag
   colorlist =
   MouseGetPos start_x, start_y
   ToolTip %A_Space%, start_x, start_y
   WinSet Transparent, 150, ahk_class tooltips_class32
   SetTimer mouse, 50
Return

mouse:
   MouseGetPos current_x, current_y
   WinMove ahk_class tooltips_class32,,,,% current_x - start_x, % current_y - start_y
   If GetKeyState("LButton","P")
      Return
   SetTimer mouse, OFF
   ToolTip
   MouseGetPos end_x, end_y
   TrayTip,,Retreiving Colors...,,1
   width  := end_x - start_x
   height := end_y - start_y
   Loop %height% {
      pixely := start_y + height - A_index - 1  ; bitmaps are written backwards
      Loop %width% {
         pixelx := start_x + A_index - 1
         PixelGetColor color,pixelx,pixely      ; get the BGR value
         StringTrimLeft color, color, 2         ; remove 0x
         colorlist = %colorlist%%color%
      }
   }
   TrayTip,,Saving Bitmap...,,1
   WriteBMP(file,colorlist,width,height,0)
   TrayTip,,Done!,,1
Return

WriteBMP(file,colors,width=16,height=16,padded=0) {
   If (!padded and StrLen(colors)/6 <> height*width   ; check if we have the right number of pixels
     or padded and StrLen(colors)/6 - (width&3)*height <> height*width)
      MsgBox Pixel Mismatch!`nThe Height*Width specified does not match the number of pixels provided, or the padding is incorrect
   If (!padded and (width&3)<>0) {                    ; bitmap needed but not provided with padding
      Loop %height% {
         StringMid row, colors, % width*6*A_index-5, % width*6
         colorspadded := colorspadded row padhex(0x0,width&3) ; add 00 bytes
      }
      colors = %colorspadded%
   }
; Create the actual bitmap, starting with the header
   width := padhex(width +0,4)         ; make width and height 4-byte words
   height:= padhex(height+0,4)
;           B M size   reserved offbits bitsize             planes bitcount (24 bit)...the rest is color table (0s)
   BMPHex = 424d00000000000000003600000028000000%width%%height%01001800000000000000000000000000000000000000000000000000%colors%

   Handle := DllCall("CreateFile",Str,file,Uint,0x40000000,Uint,0,UInt,0,UInt,4,Uint,0,UInt,0)
   Loop % StrLen(BMPHex)//2 {
     StringMid Hex, BMPHex, 2*A_Index-1, 2
     DllCall("WriteFile",UInt,Handle, UCharP,"0x" Hex, UInt,1,UIntP,UnusedVariable,UInt,0)
   }
   DllCall("CloseHandle", Uint,Handle)
}

padhex(hex,bytes) {        ; remove 0x, right-pad hex number to bytes length <= 4
   If hex > 255
      hex := (hex>>8) + ((hex&255)<<8) ; little endian coding
   If StrLen(hex) & 1
        StringReplace  hex, hex, x
   Else StringTrimLeft hex, hex, 2
   hex = %hex%000000
   StringLeft hex, hex, 2*bytes
   Return hex
}


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: specter333, sumon, XX0 and 24 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
cron
Powered by phpBB® Forum Software © phpBB Group