Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

GDI+ standard library 1.45 by tic


  • Please log in to reply
1385 replies to this topic
bobycom
  • Members
  • 40 posts
  • Last active: Apr 14 2019 07:50 AM
  • Joined: 25 Mar 2014

Thank you, Blackholyman.

I had to think about this myself. I feel so stupid now.



Frisko
  • Members
  • 3 posts
  • Last active: Feb 28 2015 01:45 PM
  • Joined: 16 Feb 2015

Hello, first of all: Thanks to tic for this great library and all the others that help to improve it!

 

Now my issue: Suppose I have an image with a non-transparent part in the middle surrounded by transparency. How do I get the dimensions of the non-transparent part only (Gdip_GetImageDimensions gives you the dimensions of the whole image).

 

I tried the functions Gdip_CreateHBITMAPFromBitmap(pBitmap, Background=0xffffffff) but that only fills transparent areas with the color specified.

 

Do I have to loop through all pixels and find the non-transparent pixels with GetPixel, then crop, then get dimensions? That would be really slow I suppose.

 

Or is there a function in GDI that I could call with DllCall() that can crop/erase transparent parts? I searched the MS Docs but couldn't find an appropriate function.

 

Maybe using a Matrix? You see, I am lost... :-) Some help please.

 

 



tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007

Hi Frisko

 

The fastest option really will just be to use machine code. It only needs to scan one line to find the first pixel from the left and right. This could be just called once to find the answer, but it would be so quick that you may as well have a reusable function to find separately the first non-transparent x from left or right

 

I don't have visual studio C++ installed any longer so can't compile this, and so is untested:

int Gdip_FirstOpaqueX(unsigned char * bitmap, int w, int d)
{
	if (d)
	{
		for (int x = 0; x < w; ++x)
		{
			if (bitmap[3+(4*x)] != 0) return x;
		}
	}
	else
	{
		for (int x = w; x > 0; --x)
		{
			if (bitmap[3+(4*x)] != 0) return x;
		}
	}
    return -1;
}

And then could be used in a standard Gdip machine code function with something like

x1 := DllCall(&_FirstOpaqueX, "ptr", Scan0, "int", w, "int", 0)
x2 := DllCall(&_FirstOpaqueX, "ptr", Scan0, "int", w, "int", 1)
opaqueWidth := x2 - x1

Let me know if you have problems using this and can direct you how to compile it (The easiest would be to install VS C++ and then just run the MCode Creator on the forums)



Frisko
  • Members
  • 3 posts
  • Last active: Feb 28 2015 01:45 PM
  • Joined: 16 Feb 2015

Hey tic,

 

thanks for your help. I took this approach and here is my solution for anybody who needs it :-)

The function finds the left/top/right and bottommost pixel that is not the color specified. The result is a rectangle with X1,Y1 and X2,Y2. The function then creates a new bitmap of this area and returns it. Basically it cuts all colored/transparent space that surrounds a solid shape the bounds of a shape. What you get is the solid shape shape cutted to its rectangular bound. Then you can get the dimensions, save it to file or whatever you want.

 

Tested with shape rectangle, square, circle, triangle, ellipsis and polygon on transparent, black, red, green and blue background.

;#####################################################################################

; Function              Gdip_CutBitmap
; Description           This function cuts colored/transparent space that surrounds the bounds of a shape
;
; pBitmap               Pointer to a bitmap
; ARGB                  The background color to cut. Default = 0x00ffffff (Full transparent)
; Dispose               Whether to dispose pBitmap or not. Default = 1 (Dispose)
;
; return                Pointer to a gdi+ bitmap

Gdip_CutBitmap(pBitmap, ARGB=0x00ffffff, Dispose=1) {
   bmpWidth := Gdip_GetImageWidth(pBitmap)
   bmpHeight:= Gdip_GetImageHeight(pBitmap)

   Gdip_LockBits(pBitmap, 0, 0, bmpWidth, bmpHeight, Stride, Scan0, BitmapData, 1)

   MCode_ImageCut := "
      (LTrim Join
      2,x86:VVdWU4PsOItEJFyLTCRgi1wkZMdEJCwAAAAAiceJwohEJCfB7xiB4gAA/wCJfCQo
      iceLRCRsweoQwe8IhcmJVCQEiXwkFIlEJDAPjpoAAACLfCRoiVwkZJCNtCYAAAAA
      i1QkZIXSflyLRCQwMdKJFCQPtkgDD7ZYAg+2aAEPtjCFyXQxieo4VCQUD5XCOFwk
      BInVD5XDCd2J8zhcJCeJ6w+VwgjaD4VvAgAAO0wkKA+FZQIAAIMEJAEB+Is0JDt0
      JGR1rYtEJEyLAIXAdRiDRCQsAYNEJDAEi0QkLDtEJGAPhXr///+LXCRki0QkbIXb
      x0QkLAAAAACJRCQwD46bAAAAi2wkYIlcJGSNtgAAAACF7X5gi0QkMDHSiRQkjXYA
      D7ZIAw+2WAIPtngBD7Ywhcl0M4n6OFQkFA+VwjhcJASJ1w+VwwnfifM4XCQnD5XD
      idqJ+wjaD4XNAQAAO0wkKA+FwwEAAIMEJAGDwASLDCQ56XWsi0QkUIsAhcB1G4NE
      JCwBi0wkaItEJCwBTCQwO0QkZA+Fd////4tcJGSLRCRgg+gBD4inAAAAi3wkYIlc
      JGSJfCQwi3wkbI0Eh4t8JGiJRCQsi0QkZIXAfmaLRCQsMdKJFCSNdgCNvCcAAAAA
      D7ZIAw+2WAIPtmgBD7Ywhcl0MYnqOFQkFA+VwjhcJASJ1Q+VwwndifM4XCQnieoP
      lcMI0w+F7wAAADtMJCgPheUAAACDBCQBAfiLNCQ7dCRkda2LRCRUiwCFwHUQg2wk
      LASDbCQwAQ+FeP///4tcJGSJ2IPoAQ+IlwAAAA+vRCRoi3wkaItsJGCJXCQwA0Qk
      bPffiXwkNIlEJCyQjXQmAIXtflaLRCQsMdKJFCSNdgAPtkgDD7ZYAg+2eAEPtjCF
      yXQpifo4VCQUD5XCOFwkBInXD5XDCd+J8zhcJCeJ+g+VwwjTdTU7TCQodS+DBCQB
      g8AEizwkOe91totEJFiLAIXAdQ+LfCQ0AXwkLINsJDABdY2DxDhbXl9dw4t8JDCL
      TCRYifiJOevXi0wkMIt0JFSJyIkO6R////+LTCRMi0QkLIkB6aH9//+LfCRQi0Qk
      LIkH6UL+//+QkJCQkJCQkA==,
      x64:QVdBVkFVQVRVV1ZTSIPsGESLlCSAAAAARTH2TGOsJJgAAABIiVQkaIuUJIgAAABM
      iUwkeEyJRCRwRInQRYnTRInVwegIQYHjAAD/AMHtGInDSIuEJKAAAABBwesQhdJE
      i4wkkAAAAEyNeAN+dg8fAEWFyX5WTIn4MdJmDx9EAABED7YAD7Zw/0QPtmD+D7Z4
      /UWFwHQqRDjjQQ+VxEE480APlcZECeZBOPpAD5XHQAj+D4VMAgAAQTnoD4VDAgAA
      g8IBTAHoRDnKdbWLAYXAdRJBg8YBSYPHBEQ7tCSIAAAAdY1FhckPji0CAABIi4Qk
      oAAAAExjvCSYAAAARTHkTI1oA4uEJIgAAABMiTwkTIt8JGiD6AFMjTSFBAAAAIlE
      JAyLhCSIAAAAhcB+S0uNPC5MiegPthAPtkj/D7Zw/kQPtkD9hdJ0J0A480APlcZB
      OMsPlcEJ8UU4wkEPlcBECMEPhacBAAA56g+FnwEAAEiDwARIOcd1vEGLB4XAdQ1B
      g8QBTAMsJEU5zHWWi0QkDIXAD4iRAAAASIu8JKAAAADB4AJMY6QkmAAAAEiYRIus
      JIgAAABMjXQHA0iLfCRwkEWFyX5UTInwMclmDx9EAAAPthBED7ZA/0QPtnj+D7Zw
      /YXSdClEOPtBD5XHRTjDQQ+VwEUJ+EE48kAPlcZBCPAPhfIAAAA56g+F6gAAAIPB
      AUwB4EQ5yXW3iweFwHUKSYPuBEGD7QF1l0SJyIPoAQ+IqQAAAA+vhCSYAAAASIu8
      JKAAAABEi6wkmAAAAESLvCSIAAAAQffdTWPtSJhMiSwkTItsJHhMjWQHA4tEJAxM
      jTSFBAAAAGYPH4QAAAAAAEWF/35HS408JkyJ4A8fQAAPthAPtkj/D7Zw/kQPtkD9
      hdJ0H0A480APlcZBOMsPlcEJ8UU4wkEPlcBECMF1MDnqdSxIg8AESDn4dcRBi0UA
      hcB1CkwDJCRBg+kBdaJIg8QYW15fXUFcQV1BXkFfw0SJyEWJTQDr2ESJ6ESJL+kY
      ////RIkxRInw6b/9//9FiSdEieDpYv7//4uEJIgAAACD6AGJRCQM6WD+//+QkJCQ
      )"
   GetImageRect := MCode(MCode_ImageCut)
   x1 := 0, y1 := 0, x2 := 0, y2 := 0
   DllCall(GetImageRect, "int*",x1, "int*",y1, "int*",x2, "int*",y2
   , "int",ARGB, "int",bmpWidth, "int",bmpHeight, "int",Stride, "Ptr",Scan0, "cdecl")

   ;MsgBox X1: %x1% Y1: %y1% , X2: %x2% Y2: %y2%

   Gdip_UnlockBits(pBitmap, BitmapData)

   dw := x2 - x1, dh := y2 - y1
   pBitmap2 := Gdip_CreateBitmap(dw, dh)
   G2 := Gdip_GraphicsFromImage(pBitmap2), Gdip_SetSmoothingMode(G2, 4), Gdip_SetInterpolationMode(G2, 7)
   Gdip_DrawImage(G2, pBitmap, 0, 0, dw, dh, x1, y1, dw, dh)
   Gdip_DeleteGraphics(G2)
   if Dispose
      Gdip_DisposeImage(pBitmap)
   return pBitmap2
}

Usage:

pBitmap1 := Gdip_CreateBitmapFromFile(imgPath)
pBitmap2 := Gdip_CutBitmap(pBitmap1)

/* Do something with pBitmap2 */

Gdip_DisposeImage(pBitmap2)

You'll need a MCode Function. I am using Bentschi's (thanks Bentschi!)

 

EDIT: Here is the C-Code the MCode is made from:

void Gdip_CutBitmap(int *Leftmost, int *Topmost, int *Rightmost, int *Bottommost, int c, int w, int h, int Stride, unsigned char *Scan0)
{
   struct ARGB
   {
      unsigned char A;
      unsigned char R;
      unsigned char G;
      unsigned char B;
   } color;

   color.A = (0xff000000 & c) >> 24;
   color.R = (0x00ff0000 & c) >> 16;
   color.G = (0x0000ff00 & c) >> 8;
   color.B = 0x000000ff & c;

   int x, y, o, A, R, G, B;
   // Leftmost pixel (X1) that is not the color described in the argument
   for (x = 0; x < w; ++x)
   {
      for (y = 0; y < h; ++y)
      {
         o = (4*x)+(y*Stride);
         A = Scan0[3+o];
         R = Scan0[2+o];
         G = Scan0[1+o];
         B = Scan0[o];

         if (A != 0 && (color.A != A || color.R != R || color.G != G || color.B != B))
         {
            Leftmost[0] = x;
            break;
         }
      }
      if (Leftmost[0])
         break;
   }
   // Topmost (Y1)
   for (y = 0; y < h; ++y)
   {
      for (x = 0; x < w; ++x)
      {
         o = (4*x)+(y*Stride);
         A = Scan0[3+o];
         R = Scan0[2+o];
         G = Scan0[1+o];
         B = Scan0[o];
         
         if (A != 0 && (color.A != A || color.R != R || color.G != G || color.B != B))
         {
            Topmost[0] = y;
            break;
         }
      }
      if (Topmost[0])
         break;
   }
   // Rightmost (X2)
   for (x = w - 1; x >= 0; --x)
   {
      for (y = 0; y < h; ++y)
      {
         o = (4*x)+(y*Stride);
         A = Scan0[3+o];
         R = Scan0[2+o];
         G = Scan0[1+o];
         B = Scan0[o];
         
         if (A != 0 && (color.A != A || color.R != R || color.G != G || color.B != B))
         {
            Rightmost[0] = x + 1;
            break;
         }
      }
      if (Rightmost[0])
         break;
   }
   // Bottommost (Y2)
   for (y = h - 1; y >= 0; --y)
   {
      for (x = 0; x < w; ++x)
      {
         o = (4*x)+(y*Stride);
         A = Scan0[3+o];
         R = Scan0[2+o];
         G = Scan0[1+o];
         B = Scan0[o];
         
         if (A != 0 && (color.A != A || color.R != R || color.G != G || color.B != B))
         {
            Bottommost[0] = y + 1;
            break;
         }
      }
      if (Bottommost[0])
         break;
   }
}


noname
  • Members
  • 650 posts
  • Last active:
  • Joined: 12 Nov 2011

Woow ...!  Thanks a lot Frisko and Tic  it enables me to try out a project i had i mind  :)


winXP  and ahk unicode


tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007

Nice work Frisko.

Could you also post your C++ in your post. It makes it easier for anyone to modify if their use-case is slightly different.



Frisko
  • Members
  • 3 posts
  • Last active: Feb 28 2015 01:45 PM
  • Joined: 16 Feb 2015

Nice work Frisko.

Could you also post your C++ in your post. It makes it easier for anyone to modify if their use-case is slightly different.

 

I updated my post.

Btw: The purpose of the function is not to extract/clip/mask a shape. The description was a bit confusing, so I changed it accordingly.



a1s2d3f4
  • Members
  • 4 posts
  • Last active: Feb 21 2015 05:30 AM
  • Joined: 20 Feb 2015

Have Win 8.1 x64.

Basic Autohotkey 1.0.48.5 (32-bit)

 

Trying to capture an area of a screen.

 

Using Gdip_ALL.ahk  

(; Gdip standard library v1.45 by tic (Tariq Porter) 07/09/11; Modifed by Rseding91 using fincs 64 bit compatible Gdip library 5/1/2013
; Supports: Basic, _L ANSi, _L Unicode x86 and _L Unicode x64
;
; Updated 2/20/2014 - fixed Gdip_CreateRegion() and Gdip_GetClipRegion() on AHK Unicode x86
; Updated 5/13/2013 - fixed Gdip_SetBitmapToClipboard() on AHK Unicode x64
;
)

Can't seem to be able to save my screenshots.

 

 pointer_to_a_bitmap := Gdip_BitmapFromScreen(0)

 

results in 0

 

Any ideas on what's going on?

 

Thanks



a1s2d3f4
  • Members
  • 4 posts
  • Last active: Feb 21 2015 05:30 AM
  • Joined: 20 Feb 2015

ok - seems like I figured out my problem - I had to do 

 

gdipToken := Gdip_Startup()



pecsabi
  • Members
  • 4 posts
  • Last active: Jun 14 2015 02:20 PM
  • Joined: 08 Aug 2014

Hi guys,

yesterday, I updated my AutoHotKey from 1.1.10.01 to 1.1.19.03 on my Win7 64bit machine. I had been using this script http://www.autohotke...-time/?p=662909for quite a while without problems. Unfortunately it stopped working after the update. To be exact, it's still working in the background, but the clock just doesn't appear on the screen any more. This is why I suspect that something is broken on the graphical side. That script was not written by me originally, I just added some non-graphics-related features, so I don't have much experience about how to go around with Gdip_All.ahk. Anyway, it was working fine with v1.1.10.01, and it is not working now. Btw, I also updated Gdip_All.ahk from the version at https://ahknet.autoh...ll/Gdip_All.ahk to the version shared by Blackholyman on Dropbox, which was updated last on 2/20/2014. Do you have any ideas, what could be the reason? I also checked the recent changes in AutoHotKey, but I couldn't find the relevant piece.
Your help is much appreciated.
Csaba



space
  • Members
  • 520 posts
  • Last active:
  • Joined: 12 Aug 2014
Support for this lib is now at http://ahkscript.org....php?f=6&t=6517

pecsabi
  • Members
  • 4 posts
  • Last active: Jun 14 2015 02:20 PM
  • Joined: 08 Aug 2014

Thank you, space!



tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007

As mentioned previously, support for legacy AHK will soon be dropped from the Gdip library as all active development has moved to AHK v1.1

 

http://ahkscript.org/

 

The Gdip library is being completely overhauled and can be viewed on the new forums and all links will be removed from these old forums in the coming months. All examples will be completely rewritten for the new library and new controls and methods will be created as well as completely new examples.

 

Development can be viewed on the new forums:

 

ahkscript.org/boards/viewtopic.php?t=6517



bichlepa
  • Members
  • 62 posts
  • Last active: Feb 19 2019 08:39 PM
  • Joined: 04 Jul 2011

Thanks for that amazing library! I use it in AutoHotFlow.



Surreall
  • Members
  • 34 posts
  • Last active: Apr 02 2015 03:50 PM
  • Joined: 07 Oct 2009

Hi there,

 

I was wondering if you can help me, i find gdip quite confusing as i am not a proficient programmer.

 

I am trying to crop an image i am searching with, can i use GDIP for that?

 

I had in mind something like this:

 

1) i use testimage.png, and would like to search the screen for a percentage of the horizontal of that image. 

So if the testimage.png is 10x100, would like to be able to crop the image horizontally, say 60%, so i am only using the first 60 pixels in my imagesearch.

 

I presume i would need to save the saved testimage.png as a temporary image, example, temporarytestimage.png.

The cut off the last number of horizontal pixels, using gdip? So if i wanted to search only 60% i would cut the image by the last 40 pixals.

Then use the new temporarytestimage.png in the imagesearch

Then delete afterwards.

 

Is all my ramblings possible with GDIP?

 

Kindest Regards

Surreall