Add capture multi screen support and update return, and remove unused files

This commit is contained in:
vcaesar 2022-01-02 18:15:15 -04:00
parent 48f1adce7e
commit 28fd0b9af6
15 changed files with 123 additions and 636 deletions

View File

@ -11,11 +11,13 @@ jobs:
- checkout
# specify any bash command here prefixed with `run: `
- run: apt update
- run: apt -y install gcc libc6-dev
libx11-dev xorg-dev libxtst-dev libpng++-dev
xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev
libxkbcommon-dev
- run:
apt -y install gcc libc6-dev
libx11-dev xorg-dev libxtst-dev
xsel xclip
# libpng++-dev
# xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev
# libxkbcommon-dev
- run: apt -y install xvfb
#
# override:

View File

@ -22,10 +22,6 @@ jobs:
- name: Get dependencies
run: |
go get -v -t -d ./...
# if [ -f Gopkg.toml ]; then
# curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
# dep ensure
# fi
- name: Build
run: go build -v .

41
base/bitmap_free_c.h Normal file
View File

@ -0,0 +1,41 @@
#include "MMBitmap.h"
#include <assert.h>
#include <string.h>
MMBitmapRef createMMBitmap_c(
uint8_t *buffer,
size_t width,
size_t height,
size_t bytewidth,
uint8_t bitsPerPixel,
uint8_t bytesPerPixel
){
MMBitmapRef bitmap = malloc(sizeof(MMBitmap));
if (bitmap == NULL) { return NULL; }
bitmap->imageBuffer = buffer;
bitmap->width = width;
bitmap->height = height;
bitmap->bytewidth = bytewidth;
bitmap->bitsPerPixel = bitsPerPixel;
bitmap->bytesPerPixel = bytesPerPixel;
return bitmap;
}
void destroyMMBitmap(MMBitmapRef bitmap) {
assert(bitmap != NULL);
if (bitmap->imageBuffer != NULL) {
free(bitmap->imageBuffer);
bitmap->imageBuffer = NULL;
}
free(bitmap);
}
void destroyMMBitmapBuffer(char * bitmapBuffer, void * hint) {
if (bitmapBuffer != NULL) {
free(bitmapBuffer);
}
}

View File

@ -1,24 +0,0 @@
#pragma once
// #ifndef BITMAP_CLASS_H
// #define BITMAP_CLASS_H
#include "../base/MMBitmap.h"
/* This file defines the class "Bitmap" for dealing with raw bitmaps. */
struct _BitmapObject {
MMBitmapRef bitmap;
MMPoint point; /* For iterator */
};
typedef struct _BitmapObject BitmapObject;
// extern PyTypeObject Bitmap_Type;
/* Returns a newly-initialized BitmapObject from the given MMBitmap.
* The reference to |bitmap| is "stolen"; i.e., only the pointer is copied, and
* the reponsibility for free()'ing the buffer is given to the |BitmapObject|.
*
* Remember to call PyType_Ready() before using this for the first time! */
BitmapObject BitmapObject_FromMMBitmap(MMBitmapRef bitmap);
// #endif /* PY_BITMAP_CLASS_H */

View File

@ -1,55 +0,0 @@
#pragma once
#ifndef BITMAP_H
#define BITMAP_H
// #include "../base/types.h"
#include "../base/MMBitmap.h"
#include "../base/MMPointArray_c.h"
/* Convenience wrapper around findBitmapInRect(), where |rect| is the bounds
* of |haystack|. */
#define findBitmapInBitmap(needle, haystack, pointPtr, tol) \
findBitmapInRect(needle, haystack, pointPtr, MMBitmapGetBounds(haystack), tol)
/* Returns 0 and sets |point| to the origin of |needle| in |haystack| if
* |needle| was found in |haystack| inside of |rect|, or returns -1 if not.
*
* |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the
* colors in the bitmaps need to match, with 0 being exact and 1 being any.
*/
int findBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack,
MMPoint *point, MMRect rect, float tolerance);
/* Convenience wrapper around findAllBitmapInRect(), where |rect| is the bounds
* of |haystack|. */
#define findAllBitmapInBitmap(needle, haystack, tolerance) \
findAllBitmapInRect(needle, haystack, \
MMBitmapGetBounds(haystack), tolerance)
/* Returns MMPointArray of all occurrences of |needle| in |haystack| inside of
* |rect|. Note that an is returned regardless of whether |needle| was found;
* check array->count to see if it actually was.
*
* |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the
* colors in the bitmaps need to match, with 0 being exact and 1 being any.
*
* Responsibility for freeing the MMPointArray with destroyMMPointArray() is
* given to the caller.
*/
MMPointArrayRef findAllBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack,
MMRect rect, float tolerance);
// #define MMRGBHexAtPoint(image, x, y) \
// hexFromMMRGB(MMRGBColorAtPoint(image, x, y))
/* Convenience wrapper around countOfBitmapInRect(), where |rect| is the bounds
* of |haystack|. */
#define countOfBitmapInBitmap(needle, haystack, tolerance) \
countOfBitmapInRect(needle, haystack, MMBitmapGetBounds(haystack), tolerance)
/* Returns the number of occurences of |needle| in |haystack| inside
* of |rect|. */
size_t countOfBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack,
MMRect rect, float tolerance);
#endif /* BITMAP_H */

View File

@ -1,270 +0,0 @@
#include "bitmap_find.h"
#include "../base/UTHashTable_c.h"
#include <assert.h>
/* Node to be used in hash table. */
struct shiftNode {
UTHashNode_HEAD /* Make structure hashable */
MMRGBHex color; /* Key */
MMPoint offset; /* Value */
};
/* --- Hash table helper functions --- */
/* Adds hex-color/offset pair to jump table. */
static void addNodeToTable(UTHashTable *table, MMRGBHex color, MMPoint offset);
/* Returns node associated with color in jump table, or NULL if it
* doesn't exist. */
static struct shiftNode *nodeForColor(UTHashTable *table, MMRGBHex color);
/* Returns nonzero (true) if table has key, or zero (false) if not. */
#define tableHasKey(table, color) (nodeForColor(table, color) != NULL)
/* --- Boyer-Moore helper functions --- */
/* Calculates the first table for use in a Boyer-Moore search algorithm.
* Table is in the form [colors: shift_values], where colors are those in
* |needle|, and the shift values are each color's distance from the rightmost
* offset. All other colors are assumed to have a shift value equal to the
* length of needle.
*/
static void initBadShiftTable(UTHashTable *jumpTable, MMBitmapRef needle);
/* Frees memory occupied by calling initBadShiftTable().
* Currently this is just an alias for destroyHashTable(). */
#define destroyBadShiftTable(jumpTable) destroyHashTable(jumpTable)
/* Returns true if |needle| is found in |haystack| at |offset|. */
static int needleAtOffset(MMBitmapRef needle, MMBitmapRef haystack,
MMPoint offset, float tolerance);
/* --- --- */
/* An modification of the Boyer-Moore-Horspool Algorithm, only applied to
* bitmaps and colors instead of strings and characters.
*
* TODO: The Boyer-Moore algorithm (with the second jump table) would probably
* be more efficient, but this was simpler (for now).
*
* The jump table (|badShiftTable|) is passed as a parameter to avoid being
* recalculated each time. It should be a pointer to a UTHashTable init'd with
* initBadShiftTable().
*
* Returns 0 and sets |point| to the starting point of |needle| in |haystack|
* if |needle| was found in |haystack|, or returns -1 if not. */
static int findBitmapInRectAt(MMBitmapRef needle,
MMBitmapRef haystack,
MMPoint *point,
MMRect rect,
float tolerance,
MMPoint startPoint,
UTHashTable *badShiftTable)
{
const size_t scanHeight = rect.size.height - needle->height;
const size_t scanWidth = rect.size.width - needle->width;
MMPoint pointOffset = startPoint;
/* const MMPoint lastPoint = MMPointMake(needle->width - 1, needle->height - 1); */
/* Sanity check */
if (needle->height > haystack->height || needle->width > haystack->width ||
!MMBitmapRectInBounds(haystack, rect)) {
return -1;
}
assert(point != NULL);
assert(needle != NULL);
assert(needle->height > 0 && needle->width > 0);
assert(haystack != NULL);
assert(haystack->height > 0 && haystack->width > 0);
assert(badShiftTable != NULL);
/* Search |haystack|, while |needle| can still be within it. */
while (pointOffset.y <= scanHeight) {
/* struct shiftNode *node = NULL;
MMRGBHex lastColor; */
while (pointOffset.x <= scanWidth) {
/* Check offset in |haystack| for |needle|. */
if (needleAtOffset(needle, haystack, pointOffset, tolerance)) {
// ++pointOffset.x;
// ++pointOffset.y;
*point = pointOffset;
return 0;
}
/* Otherwise, calculate next x offset to check. */
/*
* Note that here we are getting the skip value based on the last
* color of |needle|, no matter where we didn't match. The
* alternative of pretending that the mismatched color was the previous
* color is slower in the normal case.
*/
/* lastColor = MMRGBHexAtPoint(haystack, pointOffset.x + lastPoint.x,
pointOffset.y + lastPoint.y); */
/* TODO: This fails on certain edge cases (issue#7). */
/* When a color is encountered that does not occur in |needle|, we can
* safely skip ahead for the whole length of |needle|.
* Otherwise, use the value stored in the jump table. */
/* node = nodeForColor(badShiftTable, lastColor);
pointOffset.x += (node == NULL) ? needle->width : (node->offset).x; */
/* For now, be naive. */
++pointOffset.x;
}
pointOffset.x = rect.origin.x;
/* lastColor = MMRGBHexAtPoint(haystack, pointOffset.x + lastPoint.x,
pointOffset.y + lastPoint.y);
node = nodeForColor(badShiftTable, lastColor);
pointOffset.y += node == NULL ? lastPoint.y : (node->offset).y; */
/* TODO: The above commented out code fails at certain edge cases, e.g.:
* Needle: [B, b
* b, b,
* B, b]
* Haystack: [w, w, w, w, w
* w, w, w, w, b
* w, w, w, b, b
* w, w, w, w, b]
* The previous algorithm noticed that the first 3 x 3 block had nothing
* in common with the image, and thus, after scanning the first row,
* skipped three blocks downward to scan the next (which didn't exist,
* so the loop ended). However, the needle was hidden IN-BETWEEN this
* jump -- skipping was appropriate for scanning the column but not
* the row.
*
* I need to figure out a more optimal solution; temporarily I am just
* scanning every single y coordinate, only skipping on x's. This
* always works, but is probably not optimal.
*/
++pointOffset.y;
}
return -1;
}
int findBitmapInRect(MMBitmapRef needle,
MMBitmapRef haystack,
MMPoint *point,
MMRect rect,
float tolerance)
{
UTHashTable badShiftTable;
int ret;
initBadShiftTable(&badShiftTable, needle);
ret = findBitmapInRectAt(needle, haystack, point, rect,
tolerance, MMPointZero, &badShiftTable);
destroyBadShiftTable(&badShiftTable);
return ret;
}
MMPointArrayRef findAllBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack,
MMRect rect, float tolerance)
{
MMPointArrayRef pointArray = createMMPointArray(0);
MMPoint point = MMPointZero;
UTHashTable badShiftTable;
initBadShiftTable(&badShiftTable, needle);
while (findBitmapInRectAt(needle, haystack, &point, rect,
tolerance, point, &badShiftTable) == 0) {
const size_t scanWidth = (haystack->width - needle->width) + 1;
MMPointArrayAppendPoint(pointArray, point);
ITER_NEXT_POINT(point, scanWidth, 0);
}
destroyBadShiftTable(&badShiftTable);
return pointArray;
}
size_t countOfBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack,
MMRect rect, float tolerance)
{
size_t count = 0;
MMPoint point = MMPointZero;
UTHashTable badShiftTable;
initBadShiftTable(&badShiftTable, needle);
while (findBitmapInRectAt(needle, haystack, &point, rect,
tolerance, point, &badShiftTable) == 0) {
const size_t scanWidth = (haystack->width - needle->width) + 1;
++count;
ITER_NEXT_POINT(point, scanWidth, 0);
}
destroyBadShiftTable(&badShiftTable);
return count;
}
/* --- Boyer-Moore helper functions --- */
static void initBadShiftTable(UTHashTable *jumpTable, MMBitmapRef needle)
{
const MMPoint lastPoint = MMPointMake(needle->width - 1, needle->height - 1);
const size_t maxColors = needle->width * needle->height;
MMPoint scan;
/* Allocate max size initially to avoid a million calls to malloc(). */
initHashTable(jumpTable, maxColors, sizeof(struct shiftNode));
/* Populate jumpTable with analysis of |needle|. */
for (scan.y = lastPoint.y; ; --scan.y) {
for (scan.x = lastPoint.x; ; --scan.x) {
MMRGBHex color = MMRGBHexAtPoint(needle, scan.x, scan.y);
if (!tableHasKey(jumpTable, color)) {
addNodeToTable(jumpTable, color,
MMPointMake(needle->width - scan.x,
needle->height - scan.y));
}
if (scan.x == 0) break; /* Avoid infinite loop from unsigned type. */
}
if (scan.y == 0) break;
}
}
static int needleAtOffset(MMBitmapRef needle, MMBitmapRef haystack,
MMPoint offset, float tolerance)
{
const MMPoint lastPoint = MMPointMake(needle->width - 1, needle->height - 1);
MMPoint scan;
/* Note that |needle| is searched backwards, in accordance with the
* Boyer-Moore search algorithm. */
for (scan.y = lastPoint.y; ; --scan.y) {
for (scan.x = lastPoint.x; ; --scan.x) {
MMRGBHex ncolor = MMRGBHexAtPoint(needle, scan.x, scan.y);
MMRGBHex hcolor = MMRGBHexAtPoint(haystack, offset.x + scan.x,
offset.y + scan.y);
if (!MMRGBHexSimilarToColor(ncolor, hcolor, tolerance)) return 0;
if (scan.x == 0) break; /* Avoid infinite loop from unsigned type. */
}
if (scan.y == 0) break;
}
return 1;
}
/* --- Hash table helper functions --- */
static void addNodeToTable(UTHashTable *table,
MMRGBHex hexColor,
MMPoint offset)
{
struct shiftNode *node = getNewNode(table);
node->color = hexColor;
node->offset = offset;
UTHASHTABLE_ADD_INT(table, color, node, struct shiftNode);
}
static struct shiftNode *nodeForColor(UTHashTable *table,
MMRGBHex color)
{
struct shiftNode *uttable = table->uttable;
struct shiftNode *node;
HASH_FIND_INT(uttable, &color, node);
return node;
}

View File

@ -1,203 +0,0 @@
// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include "bitmap_class.h"
#include "bitmap_find_c.h"
#include "../base/color_find_c.h"
// #include "../screen/screen_c.h"
#include "../base/file_io_c.h"
#include "../base/pasteboard_c.h"
#include "../base/str_io_c.h"
#include <assert.h>
#include <stdio.h>
/* Returns false and sets error if |bitmap| is NULL. */
bool bitmap_ready(MMBitmapRef bitmap){
if (bitmap == NULL || bitmap->imageBuffer == NULL) {
return false;
}
return true;
}
// void bitmap_dealloc(MMBitmapRef bitmap){
// if (bitmap != NULL) {
// destroyMMBitmap(bitmap);
// bitmap = NULL;
// }
// }
bool bitmap_copy_to_pboard(MMBitmapRef bitmap){
MMPasteError err;
if (!bitmap_ready(bitmap)) return false;
if ((err = copyMMBitmapToPasteboard(bitmap)) != kMMPasteNoError) {
return false;
}
return true;
}
MMBitmapRef bitmap_deepcopy(MMBitmapRef bitmap){
return bitmap == NULL ? NULL : copyMMBitmap(bitmap);
}
MMPoint find_bitmap(MMBitmapRef bitmap, MMBitmapRef sbit, float tolerance){
MMPoint point = {-1, -1};
// printf("tolenrance=%f\n", tolerance);
if (!bitmap_ready(sbit) || !bitmap_ready(bitmap)) {
printf("bitmap is not ready yet!\n");
return point;
}
MMRect rect = MMBitmapGetBounds(sbit);
// printf("x=%d, y=%d, width=%d, height=%d\n", rect.origin.x,
// rect.origin.y, rect.size.width, rect.size.height);
if (findBitmapInRect(bitmap, sbit, &point, rect, tolerance) == 0) {
return point;
}
return point;
}
MMPointArrayRef find_every_bitmap(MMBitmapRef bitmap, MMBitmapRef sbit, float tolerance, MMPoint *list){
if (!bitmap_ready(bitmap) || !bitmap_ready(sbit)) { return NULL; }
MMPoint point;
MMPointArrayRef pointArray;
MMRect rect = MMBitmapGetBounds(sbit);
if (findBitmapInRect(bitmap, sbit, &point, rect, tolerance) == 0) {
// return NULL;
}
pointArray = findAllBitmapInRect(bitmap, sbit, rect, tolerance);
return pointArray;
}
int count_of_bitmap(MMBitmapRef bitmap, MMBitmapRef sbit, float tolerance){
if (!bitmap_ready(bitmap) || !bitmap_ready(sbit)) { return 0; }
MMRect rect = MMBitmapGetBounds(bitmap);
return countOfBitmapInRect(bitmap, sbit, rect, tolerance);
}
bool point_in_bounds(MMBitmapRef bitmap, MMPoint point){
if (!bitmap_ready(bitmap)) {
return NULL;
}
if (MMBitmapPointInBounds(bitmap, point)) {
return true;
}
return false;
}
MMBitmapRef bitmap_open(char *path, uint16_t ttype){
// MMImageType type;
MMBitmapRef bitmap;
MMIOError err;
bitmap = newMMBitmapFromFile(path, ttype, &err);
// printf("....%zd\n", bitmap->width);
return bitmap;
}
MMBitmapRef bitmap_from_string(const char *str){
size_t len = strlen(str);
MMBitmapRef bitmap;
MMBMPStringError err;
if ((bitmap = createMMBitmapFromString((unsigned char*)str, len, &err))
== NULL) {
return NULL;
}
return bitmap;
}
char *bitmap_save(MMBitmapRef bitmap, char *path, uint16_t type){
if (saveMMBitmapToFile(bitmap, path, (MMImageType) type) != 0) {
return "Could not save image to file.";
}
// destroyMMBitmap(bitmap);
return "";
}
char *tostring_bitmap(MMBitmapRef bitmap){
char *buf = NULL;
MMBMPStringError err;
buf = (char *)createStringFromMMBitmap(bitmap, &err);
return buf;
}
// char out size 200 is enough
bool bitmap_str(MMBitmapRef bitmap, char *out){
if (!bitmap_ready(bitmap)) { return false; }
sprintf(out, "<Bitmap with resolution %lu%lu, \
%u bits per pixel, and %u bytes per pixel>",
(unsigned long)bitmap->width,
(unsigned long)bitmap->height,
bitmap->bitsPerPixel,
bitmap->bytesPerPixel);
return true;
}
MMBitmapRef get_portion(MMBitmapRef bit_map, MMRect rect){
// MMRect rect;
MMBitmapRef portion = NULL;
portion = copyMMBitmapFromPortion(bit_map, rect);
return portion;
}
MMRGBHex bitmap_get_color(MMBitmapRef bitmap, size_t x, size_t y){
if (!bitmap_ready(bitmap)) { return 0; }
MMPoint point;
point = MMPointMake(x, y);
if (!MMBitmapPointInBounds(bitmap, point)) {
return 0;
}
return MMRGBHexAtPoint(bitmap, point.x, point.y);
}
MMPoint bitmap_find_color(MMBitmapRef bitmap, MMRGBHex color, float tolerance){
MMRect rect = MMBitmapGetBounds(bitmap);
MMPoint point = {-1, -1};
if (findColorInRect(bitmap, color, &point, rect, tolerance) == 0) {
return point;
}
return point;
}
MMPointArrayRef bitmap_find_every_color(MMBitmapRef bitmap, MMRGBHex color, float tolerance, MMPoint *list){
if (!bitmap_ready(bitmap)) { return NULL; }
MMRect rect = MMBitmapGetBounds(bitmap);
MMPointArrayRef pointArray;
pointArray = findAllColorInRect(bitmap, color, rect, tolerance);
return pointArray;
}
int bitmap_count_of_color(MMBitmapRef bitmap, MMRGBHex color, float tolerance){
if (!bitmap_ready(bitmap)) return 0;
MMRect rect = MMBitmapGetBounds(bitmap);
return countOfColorsInRect(bitmap, color, rect, tolerance);
}

4
go.mod
View File

@ -5,14 +5,14 @@ go 1.17
require (
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
github.com/otiai10/gosseract v2.2.1+incompatible
github.com/robotn/gohook v0.31.3
// github.com/robotn/gohook v0.31.3
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770
github.com/vcaesar/gops v0.21.3
github.com/vcaesar/imgo v0.30.0
github.com/vcaesar/keycode v0.10.0
github.com/vcaesar/tt v0.20.0
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
)

2
go.sum
View File

@ -17,8 +17,6 @@ github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robotn/gohook v0.31.3 h1:kGX8iukJ9ensVRwRKnTtdojAMQOpa6KFnXDi4OA4RaI=
github.com/robotn/gohook v0.31.3/go.mod h1:wyGik0yb4iwCfJjDprtNkTyxkgQWuKoVPQ3hkz6+6js=
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY=
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk=

View File

@ -18,6 +18,7 @@ See Requirements:
https://github.com/go-vgo/robotgo#requirements
Installation:
With Go module support (Go 1.11+), just import:
import "github.com/go-vgo/robotgo"
@ -68,7 +69,7 @@ import (
const (
// Version get the robotgo version
Version = "v0.100.0.1189, MT. Baker!"
Version = "v1.00.0.1189, MT. Baker!"
)
// GetVersion get the robotgo version
@ -81,6 +82,9 @@ var (
MouseSleep = 0
// KeySleep set the key default millisecond sleep time
KeySleep = 0
// DisplayID set the screen display id
DisplayID = -1
)
type (
@ -199,17 +203,18 @@ func RgbToHex(r, g, b uint8) C.uint32_t {
}
// GetPxColor get the pixel color return C.MMRGBHex
func GetPxColor(x, y int) C.MMRGBHex {
func GetPxColor(x, y int, displayId ...int) C.MMRGBHex {
cx := C.int32_t(x)
cy := C.int32_t(y)
color := C.get_px_color(cx, cy)
display := displayIdx(displayId...)
color := C.get_px_color(cx, cy, C.int32_t(display))
return color
}
// GetPixelColor get the pixel color return string
func GetPixelColor(x, y int) string {
return PadHex(GetPxColor(x, y))
func GetPixelColor(x, y int, displayId ...int) string {
return PadHex(GetPxColor(x, y, displayId...))
}
// GetMouseColor get the mouse pos's color
@ -218,6 +223,18 @@ func GetMouseColor() string {
return GetPixelColor(x, y)
}
func displayIdx(id ...int) int {
display := -1
if DisplayID != -1 {
display = DisplayID
}
if len(id) > 0 {
display = id[0]
}
return display
}
// SysScale get the sys scale
func SysScale() float64 {
s := C.sys_scale()
@ -244,7 +261,7 @@ func GetScreenSize() (int, int) {
// GetScreenRect get the screen rect (x, y, w, h)
func GetScreenRect(displayId ...int) Rect {
display := 0
display := -1
if len(displayId) > 0 {
display = displayId[0]
}
@ -274,8 +291,16 @@ func GetScaleSize() (int, int) {
// use `defer robotgo.FreeBitmap(bitmap)` to free the bitmap
//
// robotgo.CaptureScreen(x, y, w, h int)
func CaptureScreen(args ...int) C.MMBitmapRef {
func CaptureScreen(args ...int) CBitmap {
var x, y, w, h C.int32_t
displayId := -1
if DisplayID != -1 {
displayId = DisplayID
}
if len(args) > 4 {
displayId = args[4]
}
if len(args) > 3 {
x = C.int32_t(args[0])
@ -284,16 +309,15 @@ func CaptureScreen(args ...int) C.MMBitmapRef {
h = C.int32_t(args[3])
} else {
// Get the main screen rect.
rect := GetScreenRect()
rect := GetScreenRect(displayId)
x = C.int32_t(rect.X)
y = C.int32_t(rect.Y)
w = C.int32_t(rect.W)
h = C.int32_t(rect.H)
}
bit := C.capture_screen(x, y, w, h)
return bit
bit := C.capture_screen(x, y, w, h, C.int32_t(displayId))
return CBitmap(bit)
}
// GoCaptureScreen capture the screen and return bitmap(go struct)
@ -313,13 +337,13 @@ func CaptureImg(args ...int) image.Image {
}
// FreeBitmap free and dealloc the C bitmap
func FreeBitmap(bitmap C.MMBitmapRef) {
func FreeBitmap(bitmap CBitmap) {
// C.destroyMMBitmap(bitmap)
C.bitmap_dealloc(bitmap)
C.bitmap_dealloc(C.MMBitmapRef(bitmap))
}
// ToBitmap trans C.MMBitmapRef to Bitmap
func ToBitmap(bit C.MMBitmapRef) Bitmap {
func ToBitmap(bit CBitmap) Bitmap {
bitmap := Bitmap{
ImgBuf: (*uint8)(bit.imageBuffer),
Width: int(bit.width),
@ -332,13 +356,27 @@ func ToBitmap(bit C.MMBitmapRef) Bitmap {
return bitmap
}
// ToCBitmap trans Bitmap to C.MMBitmapRef
func ToCBitmap(bit Bitmap) CBitmap {
cbitmap := C.createMMBitmap_c(
(*C.uint8_t)(bit.ImgBuf),
C.size_t(bit.Width),
C.size_t(bit.Height),
C.size_t(bit.Bytewidth),
C.uint8_t(bit.BitsPixel),
C.uint8_t(bit.BytesPerPixel),
)
return CBitmap(cbitmap)
}
// ToImage convert C.MMBitmapRef to standard image.Image
func ToImage(bit C.MMBitmapRef) image.Image {
func ToImage(bit CBitmap) image.Image {
return ToRGBA(bit)
}
// ToRGBA convert C.MMBitmapRef to standard image.RGBA
func ToRGBA(bit C.MMBitmapRef) *image.RGBA {
func ToRGBA(bit CBitmap) *image.RGBA {
bmp1 := ToBitmap(bit)
return ToRGBAGo(bmp1)
}
@ -536,7 +574,7 @@ func MoveSmooth(x, y int, args ...interface{}) bool {
cy := C.int32_t(y)
var (
mouseDelay = 5
mouseDelay = 1
low C.double
high C.double
)

View File

@ -14,7 +14,6 @@
package robotgo
import (
"fmt"
"testing"
"github.com/vcaesar/tt"
@ -152,36 +151,6 @@ func TestKeyCode(t *testing.T) {
tt.Equal(t, "=", s)
}
func TestBitmap(t *testing.T) {
bit := CaptureScreen()
tt.NotNil(t, bit)
e := SaveBitmap(bit, "robot_test.png")
tt.Empty(t, e)
bit0 := CaptureScreen(10, 10, 20, 20)
x, y := FindBitmap(bit0)
fmt.Println("Find bitmap: ", x, y)
arr := FindAllBitmap(bit0)
fmt.Println("Find all bitmap:", arr)
tt.Equal(t, 1, len(arr))
c1 := CHex(0xAADCDC)
x, y = FindColor(c1)
fmt.Println("Find color: ", x, y)
arr = FindAllColor(c1)
fmt.Println("Find all color: ", arr)
img := ToImage(bit)
err := SavePng(img, "robot_img.png")
tt.Nil(t, err)
bit1 := OpenBitmap("robot_test.png")
b := tt.TypeOf(bit, bit1)
tt.True(t, b)
tt.NotNil(t, bit1)
}
func TestPs(t *testing.T) {
id, err := Pids()
tt.Not(t, "[]", id)

View File

@ -45,7 +45,7 @@ uint32_t color_rgb_to_hex(uint8_t r, uint8_t g, uint8_t b){
return RGB_TO_HEX(r, g, b);
}
MMRGBHex get_px_color(int32_t x, int32_t y){
MMRGBHex get_px_color(int32_t x, int32_t y, int32_t display_id) {
MMBitmapRef bitmap;
MMRGBHex color;
@ -53,7 +53,7 @@ MMRGBHex get_px_color(int32_t x, int32_t y){
return color;
}
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1));
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id);
// bitmap = MMRectMake(x, y, 1, 1);
color = MMRGBHexAtPoint(bitmap, 0, 0);
@ -62,8 +62,8 @@ MMRGBHex get_px_color(int32_t x, int32_t y){
return color;
}
char* get_pixel_color(int32_t x, int32_t y){
MMRGBHex color = get_px_color(x, y);
char* get_pixel_color(int32_t x, int32_t y, int32_t display_id) {
MMRGBHex color = get_px_color(x, y, display_id);
char* s = pad_hex(color);
return s;
@ -104,16 +104,8 @@ void bitmap_dealloc(MMBitmapRef bitmap){
}
// capture_screen capture screen
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h){
// if () {
// x = 0;
// y = 0;
// // Get screen size.
// MMSize displaySize = getMainDisplaySize();
// w = displaySize.width;
// h = displaySize.height;
// }
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h));
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id) {
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id);
// printf("%s\n", bitmap);
return bitmap;
}

View File

@ -38,7 +38,7 @@ MMSizeInt32 getMainDisplaySize(void){
MMRectInt32 getScreenRect(int32_t display_id) {
#if defined(IS_MACOSX)
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
if (display_id == 0) {
if (display_id == -1) {
displayID = CGMainDisplayID();
}
CGRect displayRect = CGDisplayBounds(displayID);

View File

@ -3,7 +3,8 @@
#define SCREENGRAB_H
#include "../base/types.h"
#include "../base/MMBitmap_c.h"
// #include "../base/MMBitmap_c.h"
#include "../base/bitmap_free_c.h"
#ifdef __cplusplus
extern "C"
@ -12,7 +13,7 @@ extern "C"
/* Returns a raw bitmap of screengrab of the display (to be destroyed()'d by
* caller), or NULL on error. */
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect);
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id);
#ifdef __cplusplus
}

View File

@ -17,22 +17,24 @@
#include <string.h>
#endif
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id){
#if defined(IS_MACOSX)
MMBitmapRef bitmap = NULL;
uint8_t *buffer = NULL;
size_t bufferSize = 0;
CGDirectDisplayID displayID = CGMainDisplayID();
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
if (displayID == -1) {
displayID = CGMainDisplayID();
}
CGImageRef image = CGDisplayCreateImageForRect(displayID,
CGRectMake(rect.origin.x, rect.origin.y, rect.size.w, rect.size.h));
if (!image) { return NULL; }
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
if (!imageData) { return NULL; }
bufferSize = CFDataGetLength(imageData);
@ -40,7 +42,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);
bitmap = createMMBitmap(buffer,
bitmap = createMMBitmap_c(buffer,
CGImageGetWidth(image),CGImageGetHeight(image),
CGImageGetBytesPerRow(image), CGImageGetBitsPerPixel(image),
CGImageGetBitsPerPixel(image) / 8);
@ -60,7 +62,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
XCloseDisplay(display);
if (image == NULL) { return NULL; }
bitmap = createMMBitmap((uint8_t *)image->data,
bitmap = createMMBitmap_c((uint8_t *)image->data,
rect.size.w, rect.size.h, (size_t)image->bytes_per_line,
(uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8);
image->data = NULL; /* Steal ownership of bitmap data so we don't have to
@ -109,7 +111,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
return NULL;
}
bitmap = createMMBitmap(NULL, rect.size.w, rect.size.h, 4 * rect.size.w,
bitmap = createMMBitmap_c(NULL, rect.size.w, rect.size.h, 4 * rect.size.w,
(uint8_t)bi.bmiHeader.biBitCount, 4);
/* Copy the data to our pixel buffer. */