1

Тема: AHK: Поиск совпадения картинки через машинный код

Решил упростить c++ функции + создать правильный алгоритм нахождения всех совпадений + упростить сам скртипт взятый отсюда:
https://github.com/MasterFocus/AutoHotk … mageSearch
и отсюда:
https://github.com/MasterFocus/AutoHotk … mageSearch
Для поиска совпадений нам нужно:
1) Haystack scan, stride, начальная точка поиска, конечная точка поиска
2) Needle scan, stride, ширина с высотой
3) Вариация от 0 до 255 и если необходимо указать прозрачый цвет в формате rgb.

setbatchlines -1
DllCall("LoadLibrary", "str", "gdiplus")
VarSetCapacity(si, 8+2*A_PtrSize, 0)
NumPut(0x1, si, "uint")
DllCall("gdiplus\GdiplusStartup", "ptr*", pToken, "ptr", &si, "ptr", 0)
MCode_ImageSearch := MCode("2,x86:VVdWU4PsJItEJFArRCRgiUQkFItsJGiDwAGJRCQci0QkVCtEJGSJRCQgg8ABhe0PhA8BAAA7RCRMD46AAgAAi0QkTA+vRCREiUQkGItEJEiJRCQMi0QkHDtEJEgPjhkCAACLRCRkhcAPjskAAABmkItEJECLfCQMx0QkCAAAAADHBCQAAAAAjQS4iUQkEItEJBiJRCQEi1QkYItEJAgx24tMJBADRCRYA0wkBIXSfxvpmwEAAI12AIPDAYPABIPBBDlcJGAPhIUBAAAPtlECD7ZwAo08Kjn+fzYp6jnWfDAPtlEBD7ZwAY08Kjn+fyEp6jnWfBsPthEPtjCNPCo5/n8OKeo51n2wjbQmAAAAAJCAeAMAdKKLfCQMjUcBOXwkFA+OVAEAAIlEJAyLRCRkhcAPjzn///+LRCQ4i3wkDOnLAAAAO0QkTA+OcQEAAItEJEwPr0QkRItsJGCJRCQMi3wkSItEJBw5+A+OLgEAAItMJGSFyQ+OkAAAAI10JgCQi0QkQIt0JAzHBCQAAAAAMduNBLiJRCQEi0wkBItEJFiNFDEB2DHJhe0Pjn0AAACJXCQI6xaNdgCAeAMAdTKDwQGDwASDwgQ5zXRdD7ZaAjhYAnXkD7ZaAThYAXXbD7YaOBh02oB4AwB01I22AAAAAI1HATl8JBQPjqAAAACLTCRkiceFyQ+Pdf///4tEJDiJOItEJDyLfCRMiTgxwIPEJFteX13DjXYAi1wkCIMEJAEDXCRciwQkA3QkRDlEJGQPhVP////rxI20JgAAAABmkIt0JFyDBCQBAXQkCIsEJIt0JEQBdCQEOUQkZA+FJf7//4tEJDiLfCQM65SLRCRMi3QkRIt8JCABdCQYg8ABO3wkTH4riUQkTOmv/f//i0QkTIt0JESLfCQgAXQkDIPAATt8JEx+CYlEJEzpoP7//4tEJDjHAP////+LRCQ8xwD/////uP/////pQP///w==,x64:QVdBVkFVQVRVV1ZTSIPsKESLpCTAAAAAi4QkoAAAAIusJMgAAABEi5wk0AAAAEQp4EyLvCSwAAAAiUQkEIPAAU2JxYlEJBiLhCSoAAAASIlMJHAp6EiJVCR4iUQkHIPAAUSJjCSIAAAARYXbD4QzAQAAO4QkmAAAAA+OxQIAAIuEJJgAAABMiYQkgAAAAEEPr8GJRCQUQY1EJP9JjUSHBEiJRCQIRIu0JJAAAACLRCQYRDnwD442AgAAhe0PjsYAAABmDx9EAABCjTy1AAAAAIt0JBQx20Ux7Uhj/0WF5A+O6wEAAExjy0hj1kuNBA9IAfpMA0wkCEgDlCSAAAAA6xgPH4AAAAAASIPABEiDwgRJOcEPhLcBAAAPtkoCRA+2QAJGjRQZRTnQfz1EKdlBOch8NQ+2SgFED7ZAAUaNFBlFOdB/I0Qp2UE5yHwbD7YKRA+2AEaNFBlFOdB/C0Qp2UE5yH2jDx8AgHgDAHSaQY1GAUQ5dCQQD45zAQAAQYnGhe0Pj0D///9Ii0QkcIu8JJgAAABEiTBIi0QkeIk4McDp+QAAADuEJJgAAAAPjpIBAACLvCSYAAAAQY1EJP9Fic4Pr7wkiAAAAEmNdIcEi5wkkAAAAItEJBg52A+OPQEAAIXtD46eAAAADx+AAAAAAESNFJ0AAAAAQYn5RTHbRTHATWPSRYXkD46oAAAASWPRSWPIRIlEJAhMAdJJjQQPSAHxTAHq6xxmDx+EAAAAAACAeAMAdTpIg8AESIPCBEg5wXRtRA+2QgJEOEACdeJED7ZCAUQ4QAF110QPtgJEOAB01IB4AwB0zg8fhAAAAAAAjUMBOVwkEA+OoQAAAInDhe0Pj2n///9Ii0QkcIu8JJgAAACJGEiLRCR4iTgxwEiDxChbXl9dQVxBXUFeQV/DkESLRCQIQYPDAUQDhCS4AAAARQHxRDndD4U3////67iQQYPFAQOcJLgAAAADtCSIAAAARDntD4Xx/f//6Zj+//+LhCSYAAAAi7QkiAAAAIt8JBwBdCQUg8ABO7wkmAAAAH4yiYQkmAAAAOmH/f//i4QkmAAAAItcJBxEAfeDwAE7nCSYAAAAfgyJhCSYAAAA6Yr+//9Ii0QkcMcA/////0iLRCR4xwD/////uP/////pOv///w==")
MCode_ImageSearchList := MCode("2,x86:VVdWU4PsSItEJHArhCSAAAAAiUQkGIPAAYusJIgAAACJRCQsi0QkdCuEJIQAAACJRCQwg8ABiUQkQIXtD4TnAQAAO0QkbA+OmAMAAItEJGyLfCRgx0QkKAAAAAAPr0QkZIlEJCCLRCRoweACiUQkOItEJGgDhCSAAAAAjQSHiUQkPItEJGyJRCQki4QkgAAAAPfYweACiUQkRItEJCw7RCRoD46qAwAAi0QkJAOEJIQAAACJRCQ0i0QkPIuUJIQAAACJRCQci0QkOIlEJBCLRCRoiUQkFIXSD47aAAAAZpCLRCQgxwQkAAAAAMdEJAgAAAAAiUQkBItEJBADRCRgiUQkDIuMJIAAAACLRCQMMduLFCQDRCQEA1QkeIXJf2XpBAMAAI10JgAPtkgCD7ZyAo08KTn+fzEp6TnOfCsPtkgBD7ZyAY08KTn+fxwp6TnOfBYPtggPtjKNPCk5/n8JKek5zn0JjXYAgHoDAHUcg8MBg8AEg8IEOZwkgAAAAA+EpAIAAIB4AwB1not8JBSDRCQQBINEJBwEjUcBOXwkGA+ErQIAAIuUJIQAAACJRCQUhdIPjyj///+LfCQoi1wkXIt0JBSLTCQkjQS9AAAAAIk0u4PHAolMAwSLXCQ0iXwkKDnZfaWLhCSAAAAAAfA5xn2Yi3QkZIt8JESLVCQcA1QkII22AAAAAI0EOo10JgCQxkADAIPABDnQdfWDwQEB8jnZdeTpYf///ztEJGwPjrEBAACLRCRsi3wkYMdEJCgAAAAAD69EJGSJRCQUi0QkaMHgAolEJDSLhCSAAAAAA0QkaI0Eh4u8JIAAAACJRCQki0QkbIlEJByLhCSAAAAA99jB4AKJRCQ4i0QkLDtEJGgPjtoBAACLRCQcA4QkhAAAAIucJIQAAACLbCRoiUQkIItEJCSJRCQQi0QkNIlEJAiF2w+OqAAAAI20JgAAAACQi0QkCANEJGDHBCQAAAAAMduJRCQEi3QkFItEJASLVCR4MckB8AHahf8PjgUBAACJXCQM6xqNdgCAegMAdTqDwQGDwASDwgQ5zw+E4QAAAIB4AwB0Iw+2WAI4WgJ12g+2WAE4WgF10Q+2GDgadNCAegMAdMqNdCYAg0QkCASNRQGDRCQQBDlsJBgPhBEBAACLnCSEAAAAicWF2w+PYP///4t0JCiLXCRci0wkHIkss40EtQAAAACDxgKJdCQoi3QkIIlMAwQ58X2vjUQ9ADnFfaeLXCRki1QkEIk8JIn3i3QkOANUJBSNtCYAAAAAjXYAjQQWjXQmAJDGQAMAg8AEOcJ19YPBAQHaOfl15Is8JOlk////x0QkKAAAAACLRCQog8RIW15fXcONtCYAAAAAkItcJAyDBCQBA1wkfIsEJAN0JGQ5hCSEAAAAD4XJ/v//6Uv///+NdgCLdCR8g0QkCAEBNCSLRCQIi3QkZAF0JAQ5hCSEAAAAD4W2/P//6Wb9//+LfCQki1wkZAFcJCCNRwE5fCQwdCeJRCQk6Sr8//+LdCQci0wkZAFMJBSNRgE5dCQwdAmJRCQc6fr9//+LRCQohcAPhEr///+LfCRAi7QkhAAAAItEJCwDhCSAAAAAjVD/jUw3/zlMJGwPjSv///85VCRoD40h////i1QkbA+vVCRki3wkYItcJGiLdCRsjVQX/CnDi3wkZI0Ugo0cnQQAAACNBBONtCYAAAAAZpCAeAMAdQTGQAP/g8AEOdB174PGAQH6OfF12otEJCiDxEhbXl9dww==,x64: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")
MCode_SetBitmapTransColor := MCode("2,x86:VVdWU4PsBItMJCSLbCQYi3wkHItEJCCLVCQohcl+YYXAfl2NTIUAMfYx2410JgCQiRwkjUQ1AOsOjbQmAAAAAIPABDnBdCkPtloCOFgCdfAPtloBOFgBdecPtho4GHXgxkADAIPABDnBddyNdCYAkIscJAH5Af6DwwE5XCQkdbCDxAQxwFteX13D,x64:U0xj2kiLVCQwRYXJfm5FhcB+aUGNQP9FicBFMdJJ99hIjUyBBEnB4AIPH4AAAAAASY0ECOsTZi4PH4QAAAAAAEiDwARIOch0Jw+2WgI4WAJ17g+2WgE4WAF15Q+2GjgYdd7GQAMASIPABEg5yHXakEGDwgFMAdlFOdF1tDHAW8M=")

needlePath := "D:\unnamed.bmp", haystackX1 := 0, haystackY1 := 0, haystackX2 := 1920, haystackY2 := 1080, variation := 0, needleTrans := 0xb51212

; Получаем необходимые данные needle из файла и если есть необходимость устанавливаем альфа-канал на нужный цвет.
DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", needlePath, "ptr*", needlePbitmap)
DllCall("gdiplus\GdipGetImageWidth", "ptr", needlePbitmap, "uint*", needleWidth)
DllCall("gdiplus\GdipGetImageHeight", "ptr", needlePbitmap, "uint*", needleHeight)
VarSetCapacity(needleRect, 16, 0)
NumPut(needleWidth, needleRect, 8, "uint")
NumPut(needleHeight, needleRect, 12, "uint")
VarSetCapacity(needleBitmapData, 16+2*A_PtrSize, 0)
DllCall("gdiplus\GdipBitmapLockBits", "ptr", needlePbitmap, "ptr", &needleRect, "uint", ReadWrite := 3, "int", Format32bppArgb := 2498570, "ptr", &needleBitmapData)
needleStride := NumGet(needleBitmapData, 8, "int")
needleScan := NumGet(needleBitmapData, 16, "ptr")
if needleTrans
{
   VarSetCapacity(TransColor, 4)
   NumPut(needleTrans, TransColor, 0, "int")
   DllCall(MCode_SetBitmapTransColor, "ptr", needleScan, "int", needleStride, "int", needleWidth, "int", needleHeight, "ptr", &TransColor, "cdecl int")
}

; Получаем необходимые данные haystack c экрана через bitblt (можно использовать любые другие апи).
hDC := DllCall("GetDC", "ptr", 0, "ptr")
hBitmap := DllCall("CreateCompatibleBitmap", "ptr", hDC, "int", haystackX2, "int", haystackY2, "ptr")
pDC := DllCall("CreateCompatibleDC", "ptr", hDC, "ptr")
oBM := DllCall("SelectObject", "ptr", pDC, "ptr", hBitmap, "ptr")
DllCall("BitBlt", "ptr", pDC, "int", 0, "int", 0, "int", haystackX2, "int", haystackY2, "ptr", hDC, "int", 0, "int", 0, "uint", SRCCOPY := 0x00CC0020)
DllCall("SelectObject", "ptr", pDC, "ptr", oBM)
DllCall("DeleteDC", "ptr", pDC)
DllCall("ReleaseDC", "ptr", 0, "ptr", hDC)
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", haystackPbitmap)
DllCall("DeleteObject", "ptr", hBitmap)
VarSetCapacity(haystackRect, 16, 0)
NumPut(haystackX2, haystackRect, 8, "uint")
NumPut(haystackY2, haystackRect, 12, "uint")
VarSetCapacity(haystackBitmapData, 16+2*A_PtrSize, 0)
DllCall("gdiplus\GdipBitmapLockBits", "ptr", haystackPbitmap, "ptr", &haystackRect, "uint", ReadWrite := 3, "int", Format32bppArgb := 2498570, "ptr", &haystackBitmapData)
haystackStride := NumGet(haystackBitmapData, 8, "int")
haystackScan := NumGet(haystackBitmapData, 16, "ptr")

; Если есть необходимость можно посмотреть, какие изображения получились откоментировав следующие 2 строчки
;gosub, haystackSave
;gosub, needleSave

; Сам поиск
if !DllCall(MCode_ImageSearch, "int*", FoundX, "int*", FoundY, "ptr", haystackScan, "int", haystackStride, "int", haystackX1, "int", haystackY1, "int", haystackX2, "int", haystackY2, "ptr", needleScan, "int", needleStride, "int", needleWidth, "int", needleHeight, "int", variation, "cdecl int")
   msgbox % FoundX "`n" FoundY
else
   msgbox not found

; Мультипоиск
VarSetCapacity(array, 1000, 0)   ;  для 125 совпадений, если надо больше, то нужно увеличить
n := DllCall(MCode_ImageSearchList, "ptr", &array, "ptr", haystackScan, "int", haystackStride, "int", haystackX1, "int", haystackY1, "int", haystackX2, "int", haystackY2, "ptr", needleScan, "int", needleStride, "int", needleWidth, "int", needleHeight, "int", variation, "cdecl int")
if (n != 0)
{
   list := "Found " n//2 " occurrences:"
   loop % n//2
      list .= "`nx" NumGet(array, (A_Index - 1)*8, "int") " y" NumGet(array, (A_Index-1)*8+4, "int")
   msgbox % list
}
else
   msgbox not found

; При необходимости  освобождаем ресурсы haystack
DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", haystackPbitmap, "ptr", &haystackBitmapData)
DllCall("gdiplus\GdipDisposeImage", "ptr", haystackPbitmap)

; При необходимости  освобождаем ресурсы needle
DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", needlePbitmap, "ptr", &needleBitmapData)
DllCall("gdiplus\GdipDisposeImage", "ptr", needlePbitmap)
return


haystackSave:
needleSave:
save := SubStr(A_ThisLabel, 1, -4)
if (save = "haystack")
   saveWidth := haystackX2, saveHeight := haystackY2
else
   saveWidth := needleWidth, saveHeight := needleHeight
DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count, "uint*", size)
VarSetCapacity(ci, size)
DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci)
Loop % count
{
   EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "ptr"), "utf-16")
   if InStr(EncoderExtensions, "*.bmp")
   {
      pCodec := &ci + idx
      break
   }
}
DllCall("gdiplus\GdipCreateBitmapFromScan0", "int", saveWidth, "int", saveHeight, "int", %save%Stride, "int", Format32bppArgb := 2498570, "ptr", %save%Scan, "ptr*", pBitmap)
DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", save "_temp.bmp", "ptr", pCodec, "uint", 0)
DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap)
return


MCode(mcode)
{
  static e := {1:4, 2:1}, c := (A_PtrSize=8) ? "x64" : "x86"
  if (!regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", m))
    return
  if (!DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", 0, "uint*", s, "ptr", 0, "ptr", 0))
    return
  p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr")
  if (c="x64")
    DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", op)
  if (DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", p, "uint*", s, "ptr", 0, "ptr", 0))
    return p
  DllCall("GlobalFree", "ptr", p)
}

c++ функции:

int Gdip_ImageSearch(int * Foundx, int * Foundy, unsigned char * HayStack, int Stride1, int sx1, int sy1, int sx2, int sy2, unsigned char * Needle, int Stride2, int nw, int nh, int v)
{
   int y1, y2, x1, x2, tx, ty;
   sx2=sx2-nw+1; sy2=sy2-nh+1;
   if (v == 0)
   {
      for (y1 = sy1; y1 < sy2; y1++)
      {
         for (x1 = sx1; x1 < sx2; x1++)
         {
            ty = y1;
            for (y2 = 0; y2 < nh; y2++)
            {
               tx = x1;
               for (x2 = 0; x2 < nw; x2++)
               {
                  if (Needle[(4*x2)+(y2*Stride2)+2] == HayStack[(4*tx)+(ty*Stride1)+2]
                  && Needle[(4*x2)+(y2*Stride2)+1] == HayStack[(4*tx)+(ty*Stride1)+1]
                  && Needle[(4*x2)+(y2*Stride2)] == HayStack[(4*tx)+(ty*Stride1)]
                  || Needle[(4*x2)+(y2*Stride2)+3] == 0)
                     tx++;
                  else
                     goto NoMatch1;
               }
               ty++;
            }
            Foundx[0] = x1; Foundy[0] = y1;
            return 0;
            NoMatch1:;
         }
      }
   }
   else
   {
      for (y1 = sy1; y1 < sy2; y1++)
      {
         for (x1 = sx1; x1 < sx2; x1++)
         {
            ty = y1;
            for (y2 = 0; y2 < nh; y2++)
            {
               tx = x1;
               for (x2 = 0; x2 < nw; x2++)
               {
                  if (Needle[(4*x2)+(y2*Stride2)+2] <= HayStack[(4*tx)+(ty*Stride1)+2]+v
                  && Needle[(4*x2)+(y2*Stride2)+2] >= HayStack[(4*tx)+(ty*Stride1)+2]-v
                  && Needle[(4*x2)+(y2*Stride2)+1] <= HayStack[(4*tx)+(ty*Stride1)+1]+v
                  && Needle[(4*x2)+(y2*Stride2)+1] >= HayStack[(4*tx)+(ty*Stride1)+1]-v
                  && Needle[(4*x2)+(y2*Stride2)] <= HayStack[(4*tx)+(ty*Stride1)]+v
                  && Needle[(4*x2)+(y2*Stride2)] >= HayStack[(4*tx)+(ty*Stride1)]-v
                  || Needle[(4*x2)+(y2*Stride2)+3] == 0)
                     tx++;
                  else
                     goto NoMatch2;
               }
               ty++;
            }
            Foundx[0] = x1; Foundy[0] = y1;
            return 0;
            NoMatch2:;
         }
      }
   }
   Foundx[0] = -1; Foundy[0] = -1;
   return -1;
}

int Gdip_ImageSearchList(int arr[], unsigned char * HayStack, int Stride1, int sx1, int sy1, int sx2, int sy2, unsigned char * Needle, int Stride2, int nw, int nh, int v)
{
   int y1, y2, x1, x2, tx, ty, hx, hy, n;
   n=0; sx2=sx2-nw+1; sy2=sy2-nh+1;
   if (v == 0)
   {
      for (y1 = sy1; y1 < sy2; y1++)
      {
         for (x1 = sx1; x1 < sx2; x1++)
         {
            ty = y1;
            for (y2 = 0; y2 < nh; y2++)
            {
               tx = x1;
               for (x2 = 0; x2 < nw; x2++)
               {
                  if (HayStack[(4*tx)+(ty*Stride1)+3] != 0)
				  {
				     if (Needle[(4*x2)+(y2*Stride2)+2] == HayStack[(4*tx)+(ty*Stride1)+2]
                     && Needle[(4*x2)+(y2*Stride2)+1] == HayStack[(4*tx)+(ty*Stride1)+1]
                     && Needle[(4*x2)+(y2*Stride2)] == HayStack[(4*tx)+(ty*Stride1)]
                     || Needle[(4*x2)+(y2*Stride2)+3] == 0)
                        tx++;
                     else
                        goto NoMatch1;
                  }
				  else
                     goto NoMatch1;
               }
               ty++;
            }
			arr[n++]=x1;
			arr[n++]=y1;
            for (hy = y1; hy < y1+nh; hy++)
            {
			   for (hx = x1; hx < x1+nw; hx++)
                  HayStack[(4*hx)+(hy*Stride1)+3] = 0;
            }
            NoMatch1:;
         }
      }
   }
   else
   {
      for (y1 = sy1; y1 < sy2; y1++)
      {
         for (x1 = sx1; x1 < sx2; x1++)
         {
            ty = y1;
            for (y2 = 0; y2 < nh; y2++)
            {
               tx = x1;
               for (x2 = 0; x2 < nw; x2++)
               {
                  if (HayStack[(4*tx)+(ty*Stride1)+3] != 0)
				  {
				     if (Needle[(4*x2)+(y2*Stride2)+2] <= HayStack[(4*tx)+(ty*Stride1)+2]+v
                     && Needle[(4*x2)+(y2*Stride2)+2] >= HayStack[(4*tx)+(ty*Stride1)+2]-v
                     && Needle[(4*x2)+(y2*Stride2)+1] <= HayStack[(4*tx)+(ty*Stride1)+1]+v
                     && Needle[(4*x2)+(y2*Stride2)+1] >= HayStack[(4*tx)+(ty*Stride1)+1]-v
                     && Needle[(4*x2)+(y2*Stride2)] <= HayStack[(4*tx)+(ty*Stride1)]+v
                     && Needle[(4*x2)+(y2*Stride2)] >= HayStack[(4*tx)+(ty*Stride1)]-v
                     || Needle[(4*x2)+(y2*Stride2)+3] == 0)
                        tx++;
                     else
                        goto NoMatch2;
                  }
                  else
                     goto NoMatch2;
               }
               ty++;
            }
			arr[n++]=x1;
			arr[n++]=y1;
            for (hy = y1; hy < y1+nh; hy++)
            {
			   for (hx = x1; hx < x1+nw; hx++)
                  HayStack[(4*hx)+(hy*Stride1)+3] = 0;
            }
            NoMatch2:;
         }
      }
   }
   if (n != 0)
   {
      sx2=sx2+nw-1; sy2=sy2+nh-1;
      for (y1 = sy1; y1 < sy2; y1++)
      {
         for (x1 = sx1; x1 < sx2; x1++)
         {
            if (HayStack[(4*x1)+(y1*Stride1)+3] == 0)
               HayStack[(4*x1)+(y1*Stride1)+3] = 255;
         }
      }
   }
   return n;
}

int Gdip_SetBitmapTransColor(unsigned char * Scan, int Stride, int Width, int Height, unsigned char * Trans)
{
   int x1, y1, index;
   for (y1 = 0; y1 < Height; y1++)
   {
      for (x1 = 0; x1 < Width; x1++)
      {
         index = (4*x1)+(y1*Stride);
         if (Scan[index+2] == Trans[2] && Scan[index+1] == Trans[1] && Scan[index+0] == Trans[0])
            Scan[index+3] = 0;
      }
   }
   return 0;
}