ich versuche folgende imagesearch funktion bei mir zu implementieren:
Code:
char* WINAPI ImageSearch(int aLeft, int aTop, int aRight, int aBottom, char *aImageFile)
// Author: ImageSearch was created by Aurelian Maga.
{
// Many of the following sections are similar to those in PixelSearch(), so they should be
// maintained together.
//Var *output_var_x = ARGVAR1; // Ok if NULL. RAW wouldn't be safe because load-time validation actually
//Var *output_var_y = ARGVAR2; // requires a minimum of zero parameters so that the output-vars can be optional.
// Set default results, both ErrorLevel and output variables, in case of early return:
//g_ErrorLevel->Assign(ERRORLEVEL_ERROR2); // 2 means error other than "image not found".
//if (output_var_x)
// output_var_x->Assign(); // Init to empty string regardless of whether we succeed here.
//if (output_var_y)
// output_var_y->Assign(); // Same.
RECT rect = {0}; // Set default (for CoordMode == "screen").
//if (!(g.CoordMode & COORD_MODE_PIXEL)) // Using relative vs. screen coordinates.
//{
// if (!GetWindowRect(GetForegroundWindow(), &rect))
// return OK; // Let ErrorLevel tell the story.
// aLeft += rect.left;
// aTop += rect.top;
// aRight += rect.left; // Add left vs. right because we're adjusting based on the position of the window.
// aBottom += rect.top; // Same.
//}
// Options are done as asterisk+option to permit future expansion.
// Set defaults to be possibly overridden by any specified options:
int aVariation = 0; // This is named aVariation vs. variation for use with the SET_COLOR_RANGE macro.
COLORREF trans_color = CLR_NONE; // The default must be a value that can't occur naturally in an image.
int icon_number = 0; // Zero means "load icon or bitmap (doesn't matter)".
int width = 0, height = 0;
// For icons, override the default to be 16x16 because that is what is sought 99% of the time.
// This new default can be overridden by explicitly specifying w0 h0:
char *cp = strrchr(aImageFile, '.');
if (cp)
{
++cp;
if (!(_stricmp(cp, "ico") && _stricmp(cp, "exe") && _stricmp(cp, "dll")))
width = GetSystemMetrics(SM_CXSMICON), height = GetSystemMetrics(SM_CYSMICON);
}
char color_name[32], *dp;
cp = omit_leading_whitespace(aImageFile); // But don't alter aImageFile yet in case it contains literal whitespace we want to retain.
while (*cp == '*')
{
++cp;
switch (toupper(*cp))
{
case 'W': width = ATOI(cp + 1); break;
case 'H': height = ATOI(cp + 1); break;
default:
if (!_strnicmp(cp, "Icon", 4))
{
cp += 4; // Now it's the character after the word.
icon_number = ATOI(cp); // LoadPicture() correctly handles any negative value.
}
else if (!_strnicmp(cp, "Trans", 5))
{
cp += 5; // Now it's the character after the word.
// Isolate the color name/number for ColorNameToBGR():
strlcpy(color_name, cp, sizeof(color_name));
if (dp = StrChrAny(color_name, " \t")) // Find space or tab, if any.
*dp = '\0';
// Fix for v1.0.44.10: Treat trans_color as containing an RGB value (not BGR) so that it matches
// the documented behavior. In older versions, a specified color like "TransYellow" was wrong in
// every way (inverted) and a specified numeric color like "Trans0xFFFFAA" was treated as BGR vs. RGB.
trans_color = ColorNameToBGR(color_name);
if (trans_color == CLR_NONE) // A matching color name was not found, so assume it's in hex format.
// It seems strtol() automatically handles the optional leading "0x" if present:
trans_color = strtol(color_name, NULL, 16);
// if color_name did not contain something hex-numeric, black (0x00) will be assumed,
// which seems okay given how rare such a problem would be.
else
trans_color = bgr_to_rgb(trans_color); // v1.0.44.10: See fix/comment above.
}
else // Assume it's a number since that's the only other asterisk-option.
{
aVariation = ATOI(cp); // Seems okay to support hex via ATOI because the space after the number is documented as being mandatory.
if (aVariation < 0)
aVariation = 0;
if (aVariation > 255)
aVariation = 255;
// Note: because it's possible for filenames to start with a space (even though Explorer itself
// won't let you create them that way), allow exactly one space between end of option and the
// filename itself:
}
} // switch()
if ( !(cp = StrChrAny(cp, " \t")) ) // Find the first space or tab after the option.
return "0"; //new
// return OK; // Bad option/format. Let ErrorLevel tell the story.
// Now it's the space or tab (if there is one) after the option letter. Advance by exactly one character
// because only one space or tab is considered the delimiter. Any others are considered to be part of the
// filename (though some or all OSes might simply ignore them or tolerate them as first-try match criteria).
aImageFile = ++cp; // This should now point to another asterisk or the filename itself.
// Above also serves to reset the filename to omit the option string whenever at least one asterisk-option is present.
cp = omit_leading_whitespace(cp); // This is done to make it more tolerant of having more than one space/tab between options.
}
// Update: Transparency is now supported in icons by using the icon's mask. In addition, an attempt
// is made to support transparency in GIF, PNG, and possibly TIF files via the *Trans option, which
// assumes that one color in the image is transparent. In GIFs not loaded via GDIPlus, the transparent
// color might always been seen as pure white, but when GDIPlus is used, it's probably always black
// like it is in PNG -- however, this will not relied upon, at least not until confirmed.
// OLDER/OBSOLETE comment kept for background:
// For now, images that can't be loaded as bitmaps (icons and cursors) are not supported because most
// icons have a transparent background or color present, which the image search routine here is
// probably not equipped to handle (since the transparent color, when shown, typically reveals the
// color of whatever is behind it; thus screen pixel color won't match image's pixel color).
// So currently, only BMP and GIF seem to work reliably, though some of the other GDIPlus-supported
// formats might work too.
int image_type;
HBITMAP hbitmap_image = LoadPicture(aImageFile, width, height, image_type, icon_number, false);
// The comment marked OBSOLETE below is no longer true because the elimination of the high-byte via
// 0x00FFFFFF seems to have fixed it. But "true" is still not passed because that should increase
// consistency when GIF/BMP/ICO files are used by a script on both Win9x and other OSs (since the
// same loading method would be used via "false" for these formats across all OSes).
// OBSOLETE: Must not pass "true" with the above because that causes bitmaps and gifs to be not found
// by the search. In other words, nothing works. Obsolete comment: Pass "true" so that an attempt
// will be made to load icons as bitmaps if GDIPlus is available.
if (!hbitmap_image)
return "0"; // new
// return OK; // Let ErrorLevel tell the story.
HDC hdc = GetDC(NULL);
if (!hdc)
{
DeleteObject(hbitmap_image);
return "0"; // new
// return OK; // Let ErrorLevel tell the story.
}
// From this point on, "goto end" will assume hdc and hbitmap_image are non-NULL, but that the below
// might still be NULL. Therefore, all of the following must be initialized so that the "end"
// label can detect them:
HDC sdc = NULL;
HBITMAP hbitmap_screen = NULL;
LPCOLORREF image_pixel = NULL, screen_pixel = NULL, image_mask = NULL;
HGDIOBJ sdc_orig_select = NULL;
bool found = false; // Must init here for use by "goto end".
bool image_is_16bit;
LONG image_width, image_height;
if (image_type == IMAGE_ICON)
{
// Must be done prior to IconToBitmap() since it deletes (HICON)hbitmap_image:
ICONINFO ii;
if (GetIconInfo((HICON)hbitmap_image, &ii))
{
// If the icon is monochrome (black and white), ii.hbmMask will contain twice as many pixels as
// are actually in the icon. But since the top half of the pixels are the AND-mask, it seems
// okay to get all the pixels given the rarity of monochrome icons. This scenario should be
// handled properly because: 1) the variables image_height and image_width will be overridden
// further below with the correct icon dimensions; 2) Only the first half of the pixels within
// the image_mask array will actually be referenced by the transparency checker in the loops,
// and that first half is the AND-mask, which is the transparency part that is needed. The
// second half, the XOR part, is not needed and thus ignored. Also note that if width/height
// required the icon to be scaled, LoadPicture() has already done that directly to the icon,
// so ii.hbmMask should already be scaled to match the size of the bitmap created later below.
image_mask = getbits(ii.hbmMask, hdc, image_width, image_height, image_is_16bit, 1);
DeleteObject(ii.hbmColor); // DeleteObject() probably handles NULL okay since few MSDN/other examples ever check for NULL.
DeleteObject(ii.hbmMask);
}
if ( !(hbitmap_image = IconToBitmap((HICON)hbitmap_image, true)) )
return "0"; //new
// return OK; // Let ErrorLevel tell the story.
}
if ( !(image_pixel = getbits(hbitmap_image, hdc, image_width, image_height, image_is_16bit)) )
goto end;
// Create an empty bitmap to hold all the pixels currently visible on the screen that lie within the search area:
int search_width = aRight - aLeft + 1;
int search_height = aBottom - aTop + 1;
if ( !(sdc = CreateCompatibleDC(hdc)) || !(hbitmap_screen = CreateCompatibleBitmap(hdc, search_width, search_height)) )
goto end;
if ( !(sdc_orig_select = SelectObject(sdc, hbitmap_screen)) )
goto end;
// Copy the pixels in the search-area of the screen into the DC to be searched:
if ( !(BitBlt(sdc, 0, 0, search_width, search_height, hdc, aLeft, aTop, SRCCOPY)) )
goto end;
LONG screen_width, screen_height;
bool screen_is_16bit;
if ( !(screen_pixel = getbits(hbitmap_screen, sdc, screen_width, screen_height, screen_is_16bit)) )
goto end;
LONG image_pixel_count = image_width * image_height;
LONG screen_pixel_count = screen_width * screen_height;
int i, j, k, x, y; // Declaring as "register" makes no performance difference with current compiler, so let the compiler choose which should be registers.
// If either is 16-bit, convert *both* to the 16-bit-compatible 32-bit format:
if (image_is_16bit || screen_is_16bit)
{
if (trans_color != CLR_NONE)
trans_color &= 0x00F8F8F8; // Convert indicated trans-color to be compatible with the conversion below.
for (i = 0; i < screen_pixel_count; ++i)
screen_pixel[i] &= 0x00F8F8F8; // Highest order byte must be masked to zero for consistency with use of 0x00FFFFFF below.
for (i = 0; i < image_pixel_count; ++i)
image_pixel[i] &= 0x00F8F8F8; // Same.
}
// v1.0.44.03: The below is now done even for variation>0 mode so its results are consistent with those of
// non-variation mode. This is relied upon by variation=0 mode but now also by the following line in the
// variation>0 section:
// || image_pixel[j] == trans_color
// Without this change, there are cases where variation=0 would find a match but a higher variation
// (for the same search) wouldn't.
for (i = 0; i < image_pixel_count; ++i)
image_pixel[i] &= 0x00FFFFFF;
// Search the specified region for the first occurrence of the image:
if (aVariation < 1) // Caller wants an exact match.
{
// Concerning the following use of 0x00FFFFFF, the use of 0x00F8F8F8 above is related (both have high order byte 00).
// The following needs to be done only when shades-of-variation mode isn't in effect because
// shades-of-variation mode ignores the high-order byte due to its use of macros such as GetRValue().
// This transformation incurs about a 15% performance decrease (percentage is fairly constant since
// it is proportional to the search-region size, which tends to be much larger than the search-image and
// is therefore the primary determination of how long the loops take). But it definitely helps find images
// more successfully in some cases. For example, if a PNG file is displayed in a GUI window, this
// transformation allows certain bitmap search-images to be found via variation==0 when they otherwise
// would require variation==1 (possibly the variation==1 success is just a side-effect of it
// ignoring the high-order byte -- maybe a much higher variation would be needed if the high
// order byte were also subject to the same shades-of-variation analysis as the other three bytes [RGB]).
for (i = 0; i < screen_pixel_count; ++i)
screen_pixel[i] &= 0x00FFFFFF;
for (i = 0; i < screen_pixel_count; ++i)
{
// Unlike the variation-loop, the following one uses a first-pixel optimization to boost performance
// by about 10% because it's only 3 extra comparisons and exact-match mode is probably used more often.
// Before even checking whether the other adjacent pixels in the region match the image, ensure
// the image does not extend past the right or bottom edges of the current part of the search region.
// This is done for performance but more importantly to prevent partial matches at the edges of the
// search region from being considered complete matches.
// The following check is ordered for short-circuit performance. In addition, image_mask, if
// non-NULL, is used to determine which pixels are transparent within the image and thus should
// match any color on the screen.
if ((screen_pixel[i] == image_pixel[0] // A screen pixel has been found that matches the image's first pixel.
|| image_mask && image_mask[0] // Or: It's an icon's transparent pixel, which matches any color.
|| image_pixel[0] == trans_color) // This should be okay even if trans_color==CLR_NONE, since CLR_NONE should never occur naturally in the image.
&& image_height <= screen_height - i/screen_width // Image is short enough to fit in the remaining rows of the search region.
&& image_width <= screen_width - i%screen_width) // Image is narrow enough not to exceed the right-side boundary of the search region.
{
// Check if this candidate region -- which is a subset of the search region whose height and width
// matches that of the image -- is a pixel-for-pixel match of the image.
for (found = true, x = 0, y = 0, j = 0, k = i; j < image_pixel_count; ++j)
{
if (!(found = (screen_pixel[k] == image_pixel[j] // At least one pixel doesn't match, so this candidate is discarded.
|| image_mask && image_mask[j] // Or: It's an icon's transparent pixel, which matches any color.
|| image_pixel[j] == trans_color))) // This should be okay even if trans_color==CLR_NONE, since CLR none should never occur naturally in the image.
break;
if (++x < image_width) // We're still within the same row of the image, so just move on to the next screen pixel.
++k;
else // We're starting a new row of the image.
{
x = 0; // Return to the leftmost column of the image.
++y; // Move one row downward in the image.
// Move to the next row within the current-candiate region (not the entire search region).
// This is done by moving vertically downward from "i" (which is the upper-left pixel of the
// current-candidate region) by "y" rows.
k = i + y*screen_width; // Verified correct.
}
}
if (found) // Complete match found.
break;
}
}
}
else // Allow colors to vary by aVariation shades; i.e. approximate match is okay.
{
// The following section is part of the first-pixel-check optimization that improves performance by
// 15% or more depending on where and whether a match is found. This section and one the follows
// later is commented out to reduce code size.
// Set high/low range for the first pixel of the image since it is the pixel most often checked
// (i.e. for performance).
//BYTE search_red1 = GetBValue(image_pixel[0]); // Because it's RGB vs. BGR, the B value is fetched, not R (though it doesn't matter as long as everything is internally consistent here).
//BYTE search_green1 = GetGValue(image_pixel[0]);
//BYTE search_blue1 = GetRValue(image_pixel[0]); // Same comment as above.
//BYTE red_low1 = (aVariation > search_red1) ? 0 : search_red1 - aVariation;
//BYTE green_low1 = (aVariation > search_green1) ? 0 : search_green1 - aVariation;
//BYTE blue_low1 = (aVariation > search_blue1) ? 0 : search_blue1 - aVariation;
//BYTE red_high1 = (aVariation > 0xFF - search_red1) ? 0xFF : search_red1 + aVariation;
//BYTE green_high1 = (aVariation > 0xFF - search_green1) ? 0xFF : search_green1 + aVariation;
//BYTE blue_high1 = (aVariation > 0xFF - search_blue1) ? 0xFF : search_blue1 + aVariation;
// Above relies on the fact that the 16-bit conversion higher above was already done because like
// in PixelSearch, it seems more appropriate to do the 16-bit conversion prior to setting the range
// of high and low colors (vs. than applying 0xF8 to each of the high/low values individually).
BYTE red, green, blue;
BYTE search_red, search_green, search_blue;
BYTE red_low, green_low, blue_low, red_high, green_high, blue_high;
// The following loop is very similar to its counterpart above that finds an exact match, so maintain
// them together and see above for more detailed comments about it.
for (i = 0; i < screen_pixel_count; ++i)
{
// The following is commented out to trade code size reduction for performance (see comment above).
//red = GetBValue(screen_pixel[i]); // Because it's RGB vs. BGR, the B value is fetched, not R (though it doesn't matter as long as everything is internally consistent here).
//green = GetGValue(screen_pixel[i]);
//blue = GetRValue(screen_pixel[i]);
//if ((red >= red_low1 && red <= red_high1
// && green >= green_low1 && green <= green_high1
// && blue >= blue_low1 && blue <= blue_high1 // All three color components are a match, so this screen pixel matches the image's first pixel.
// || image_mask && image_mask[0] // Or: It's an icon's transparent pixel, which matches any color.
// || image_pixel[0] == trans_color) // This should be okay even if trans_color==CLR_NONE, since CLR none should never occur naturally in the image.
// && image_height <= screen_height - i/screen_width // Image is short enough to fit in the remaining rows of the search region.
// && image_width <= screen_width - i%screen_width) // Image is narrow enough not to exceed the right-side boundary of the search region.
// Instead of the above, only this abbreviated check is done:
if (image_height <= screen_height - i/screen_width // Image is short enough to fit in the remaining rows of the search region.
&& image_width <= screen_width - i%screen_width) // Image is narrow enough not to exceed the right-side boundary of the search region.
{
// Since the first pixel is a match, check the other pixels.
for (found = true, x = 0, y = 0, j = 0, k = i; j < image_pixel_count; ++j)
{
search_red = GetBValue(image_pixel[j]);
search_green = GetGValue(image_pixel[j]);
search_blue = GetRValue(image_pixel[j]);
SET_COLOR_RANGE
red = GetBValue(screen_pixel[k]);
green = GetGValue(screen_pixel[k]);
blue = GetRValue(screen_pixel[k]);
if (!(found = red >= red_low && red <= red_high
&& green >= green_low && green <= green_high
&& blue >= blue_low && blue <= blue_high
|| image_mask && image_mask[j] // Or: It's an icon's transparent pixel, which matches any color.
|| image_pixel[j] == trans_color)) // This should be okay even if trans_color==CLR_NONE, since CLR_NONE should never occur naturally in the image.
break; // At least one pixel doesn't match, so this candidate is discarded.
if (++x < image_width) // We're still within the same row of the image, so just move on to the next screen pixel.
++k;
else // We're starting a new row of the image.
{
x = 0; // Return to the leftmost column of the image.
++y; // Move one row downward in the image.
k = i + y*screen_width; // Verified correct.
}
}
if (found) // Complete match found.
break;
}
}
}
//if (!found) // Must override ErrorLevel to its new value prior to the label below.
// g_ErrorLevel->Assign(ERRORLEVEL_ERROR); // "1" indicates search completed okay, but didn't find it.
end:
// If found==false when execution reaches here, ErrorLevel is already set to the right value, so just
// clean up then return.
ReleaseDC(NULL, hdc);
DeleteObject(hbitmap_image);
if (sdc)
{
if (sdc_orig_select) // i.e. the original call to SelectObject() didn't fail.
SelectObject(sdc, sdc_orig_select); // Probably necessary to prevent memory leak.
DeleteDC(sdc);
}
if (hbitmap_screen)
DeleteObject(hbitmap_screen);
if (image_pixel)
free(image_pixel);
if (image_mask)
free(image_mask);
if (screen_pixel)
free(screen_pixel);
if (!found) // Let ErrorLevel, which is either "1" or "2" as set earlier, tell the story.
return "0";
// Otherwise, success. Calculate xpos and ypos of where the match was found and adjust
// coords to make them relative to the position of the target window (rect will contain
// zeroes if this doesn't need to be done):
//if (output_var_x && !output_var_x->Assign((aLeft + i%screen_width) - rect.left))
// return FAIL;
//if (output_var_y && !output_var_y->Assign((aTop + i/screen_width) - rect.top))
// return FAIL;
int locx,locy;
//return g_ErrorLevel->Assign(ERRORLEVEL_NONE); // Indicate success.
if (found)
{
locx = (aLeft + i%screen_width) - rect.left;
locy = (aTop + i/screen_width) - rect.top;
// printf("\nFOUND!!!!%d %d",locx,locy);
sprintf_s(answer,"1|%d|%d|%d|%d",locx,locy,image_width,image_height);
return answer;
//return "ZZ";
}
return "0";
}
das funktioniert soweit auch ganz super doch wenn ich die funktion dann in meinem main programm aufrufen möchte mit :
Code:
[c] answer = ImageSearch(0,0,1920,1080,"c:\\pic.bmp"); std::cout << "ImageSearch Fehler (id: " << GetLastError() << ")" << std::endl;[/c]
springt er an der stelle
Code:
[c] int image_type; HBITMAP hbitmap_image = LoadPicture(aImageFile, width, height, image_type, icon_number, false); if (!hbitmap_image) return "0"; [/c]
der aufruf ist so wie im ichs in der bsp .cpp gefunden habe...(ohne error code)..., ich hab auch schon einfach "pic.bmp" versucht und die in den projektordner gepackt...selbes problem...hat hier jemand ne idee bzw erfahrung mit der imagesearchfunktion?`







