mirror of
https://github.com/go-vgo/robotgo.git
synced 2025-06-01 14:43:55 +00:00
Add capture multi screen support and update return, and remove unused files
This commit is contained in:
parent
48f1adce7e
commit
28fd0b9af6
@ -11,11 +11,13 @@ jobs:
|
|||||||
- checkout
|
- checkout
|
||||||
# specify any bash command here prefixed with `run: `
|
# specify any bash command here prefixed with `run: `
|
||||||
- run: apt update
|
- run: apt update
|
||||||
- run: apt -y install gcc libc6-dev
|
- run:
|
||||||
libx11-dev xorg-dev libxtst-dev libpng++-dev
|
apt -y install gcc libc6-dev
|
||||||
xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev
|
libx11-dev xorg-dev libxtst-dev
|
||||||
libxkbcommon-dev
|
|
||||||
xsel xclip
|
xsel xclip
|
||||||
|
# libpng++-dev
|
||||||
|
# xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev
|
||||||
|
# libxkbcommon-dev
|
||||||
- run: apt -y install xvfb
|
- run: apt -y install xvfb
|
||||||
#
|
#
|
||||||
# override:
|
# override:
|
||||||
|
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@ -22,10 +22,6 @@ jobs:
|
|||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
run: |
|
run: |
|
||||||
go get -v -t -d ./...
|
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
|
- name: Build
|
||||||
run: go build -v .
|
run: go build -v .
|
||||||
|
41
base/bitmap_free_c.h
Normal file
41
base/bitmap_free_c.h
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
@ -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
4
go.mod
@ -5,14 +5,14 @@ go 1.17
|
|||||||
require (
|
require (
|
||||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
|
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
|
||||||
github.com/otiai10/gosseract v2.2.1+incompatible
|
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/xgb v0.0.0-20190912153532-2cb92d044934
|
||||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770
|
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770
|
||||||
github.com/vcaesar/gops v0.21.3
|
github.com/vcaesar/gops v0.21.3
|
||||||
github.com/vcaesar/imgo v0.30.0
|
github.com/vcaesar/imgo v0.30.0
|
||||||
github.com/vcaesar/keycode v0.10.0
|
github.com/vcaesar/keycode v0.10.0
|
||||||
github.com/vcaesar/tt v0.20.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
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
2
go.sum
2
go.sum
@ -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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY=
|
||||||
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
|
github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=
|
||||||
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk=
|
github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk=
|
||||||
|
72
robotgo.go
72
robotgo.go
@ -18,6 +18,7 @@ See Requirements:
|
|||||||
https://github.com/go-vgo/robotgo#requirements
|
https://github.com/go-vgo/robotgo#requirements
|
||||||
|
|
||||||
Installation:
|
Installation:
|
||||||
|
|
||||||
With Go module support (Go 1.11+), just import:
|
With Go module support (Go 1.11+), just import:
|
||||||
import "github.com/go-vgo/robotgo"
|
import "github.com/go-vgo/robotgo"
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Version get the robotgo version
|
// Version get the robotgo version
|
||||||
Version = "v0.100.0.1189, MT. Baker!"
|
Version = "v1.00.0.1189, MT. Baker!"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetVersion get the robotgo version
|
// GetVersion get the robotgo version
|
||||||
@ -81,6 +82,9 @@ var (
|
|||||||
MouseSleep = 0
|
MouseSleep = 0
|
||||||
// KeySleep set the key default millisecond sleep time
|
// KeySleep set the key default millisecond sleep time
|
||||||
KeySleep = 0
|
KeySleep = 0
|
||||||
|
|
||||||
|
// DisplayID set the screen display id
|
||||||
|
DisplayID = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -199,17 +203,18 @@ func RgbToHex(r, g, b uint8) C.uint32_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPxColor get the pixel color return C.MMRGBHex
|
// 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)
|
cx := C.int32_t(x)
|
||||||
cy := C.int32_t(y)
|
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
|
return color
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPixelColor get the pixel color return string
|
// GetPixelColor get the pixel color return string
|
||||||
func GetPixelColor(x, y int) string {
|
func GetPixelColor(x, y int, displayId ...int) string {
|
||||||
return PadHex(GetPxColor(x, y))
|
return PadHex(GetPxColor(x, y, displayId...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMouseColor get the mouse pos's color
|
// GetMouseColor get the mouse pos's color
|
||||||
@ -218,6 +223,18 @@ func GetMouseColor() string {
|
|||||||
return GetPixelColor(x, y)
|
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
|
// SysScale get the sys scale
|
||||||
func SysScale() float64 {
|
func SysScale() float64 {
|
||||||
s := C.sys_scale()
|
s := C.sys_scale()
|
||||||
@ -244,7 +261,7 @@ func GetScreenSize() (int, int) {
|
|||||||
|
|
||||||
// GetScreenRect get the screen rect (x, y, w, h)
|
// GetScreenRect get the screen rect (x, y, w, h)
|
||||||
func GetScreenRect(displayId ...int) Rect {
|
func GetScreenRect(displayId ...int) Rect {
|
||||||
display := 0
|
display := -1
|
||||||
if len(displayId) > 0 {
|
if len(displayId) > 0 {
|
||||||
display = displayId[0]
|
display = displayId[0]
|
||||||
}
|
}
|
||||||
@ -274,8 +291,16 @@ func GetScaleSize() (int, int) {
|
|||||||
// use `defer robotgo.FreeBitmap(bitmap)` to free the bitmap
|
// use `defer robotgo.FreeBitmap(bitmap)` to free the bitmap
|
||||||
//
|
//
|
||||||
// robotgo.CaptureScreen(x, y, w, h int)
|
// 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
|
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 {
|
if len(args) > 3 {
|
||||||
x = C.int32_t(args[0])
|
x = C.int32_t(args[0])
|
||||||
@ -284,16 +309,15 @@ func CaptureScreen(args ...int) C.MMBitmapRef {
|
|||||||
h = C.int32_t(args[3])
|
h = C.int32_t(args[3])
|
||||||
} else {
|
} else {
|
||||||
// Get the main screen rect.
|
// Get the main screen rect.
|
||||||
rect := GetScreenRect()
|
rect := GetScreenRect(displayId)
|
||||||
|
|
||||||
x = C.int32_t(rect.X)
|
x = C.int32_t(rect.X)
|
||||||
y = C.int32_t(rect.Y)
|
y = C.int32_t(rect.Y)
|
||||||
w = C.int32_t(rect.W)
|
w = C.int32_t(rect.W)
|
||||||
h = C.int32_t(rect.H)
|
h = C.int32_t(rect.H)
|
||||||
}
|
}
|
||||||
|
|
||||||
bit := C.capture_screen(x, y, w, h)
|
bit := C.capture_screen(x, y, w, h, C.int32_t(displayId))
|
||||||
return bit
|
return CBitmap(bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoCaptureScreen capture the screen and return bitmap(go struct)
|
// 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
|
// FreeBitmap free and dealloc the C bitmap
|
||||||
func FreeBitmap(bitmap C.MMBitmapRef) {
|
func FreeBitmap(bitmap CBitmap) {
|
||||||
// C.destroyMMBitmap(bitmap)
|
// C.destroyMMBitmap(bitmap)
|
||||||
C.bitmap_dealloc(bitmap)
|
C.bitmap_dealloc(C.MMBitmapRef(bitmap))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToBitmap trans C.MMBitmapRef to Bitmap
|
// ToBitmap trans C.MMBitmapRef to Bitmap
|
||||||
func ToBitmap(bit C.MMBitmapRef) Bitmap {
|
func ToBitmap(bit CBitmap) Bitmap {
|
||||||
bitmap := Bitmap{
|
bitmap := Bitmap{
|
||||||
ImgBuf: (*uint8)(bit.imageBuffer),
|
ImgBuf: (*uint8)(bit.imageBuffer),
|
||||||
Width: int(bit.width),
|
Width: int(bit.width),
|
||||||
@ -332,13 +356,27 @@ func ToBitmap(bit C.MMBitmapRef) Bitmap {
|
|||||||
return 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
|
// ToImage convert C.MMBitmapRef to standard image.Image
|
||||||
func ToImage(bit C.MMBitmapRef) image.Image {
|
func ToImage(bit CBitmap) image.Image {
|
||||||
return ToRGBA(bit)
|
return ToRGBA(bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToRGBA convert C.MMBitmapRef to standard image.RGBA
|
// ToRGBA convert C.MMBitmapRef to standard image.RGBA
|
||||||
func ToRGBA(bit C.MMBitmapRef) *image.RGBA {
|
func ToRGBA(bit CBitmap) *image.RGBA {
|
||||||
bmp1 := ToBitmap(bit)
|
bmp1 := ToBitmap(bit)
|
||||||
return ToRGBAGo(bmp1)
|
return ToRGBAGo(bmp1)
|
||||||
}
|
}
|
||||||
@ -536,7 +574,7 @@ func MoveSmooth(x, y int, args ...interface{}) bool {
|
|||||||
cy := C.int32_t(y)
|
cy := C.int32_t(y)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mouseDelay = 5
|
mouseDelay = 1
|
||||||
low C.double
|
low C.double
|
||||||
high C.double
|
high C.double
|
||||||
)
|
)
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
package robotgo
|
package robotgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/vcaesar/tt"
|
"github.com/vcaesar/tt"
|
||||||
@ -152,36 +151,6 @@ func TestKeyCode(t *testing.T) {
|
|||||||
tt.Equal(t, "=", s)
|
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) {
|
func TestPs(t *testing.T) {
|
||||||
id, err := Pids()
|
id, err := Pids()
|
||||||
tt.Not(t, "[]", id)
|
tt.Not(t, "[]", id)
|
||||||
|
@ -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);
|
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;
|
MMBitmapRef bitmap;
|
||||||
MMRGBHex color;
|
MMRGBHex color;
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ MMRGBHex get_px_color(int32_t x, int32_t y){
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1));
|
bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id);
|
||||||
// bitmap = MMRectMake(x, y, 1, 1);
|
// bitmap = MMRectMake(x, y, 1, 1);
|
||||||
|
|
||||||
color = MMRGBHexAtPoint(bitmap, 0, 0);
|
color = MMRGBHexAtPoint(bitmap, 0, 0);
|
||||||
@ -62,8 +62,8 @@ MMRGBHex get_px_color(int32_t x, int32_t y){
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* get_pixel_color(int32_t x, int32_t y){
|
char* get_pixel_color(int32_t x, int32_t y, int32_t display_id) {
|
||||||
MMRGBHex color = get_px_color(x, y);
|
MMRGBHex color = get_px_color(x, y, display_id);
|
||||||
|
|
||||||
char* s = pad_hex(color);
|
char* s = pad_hex(color);
|
||||||
return s;
|
return s;
|
||||||
@ -104,16 +104,8 @@ void bitmap_dealloc(MMBitmapRef bitmap){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// capture_screen capture screen
|
// capture_screen capture screen
|
||||||
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h){
|
MMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id) {
|
||||||
// if () {
|
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id);
|
||||||
// x = 0;
|
|
||||||
// y = 0;
|
|
||||||
// // Get screen size.
|
|
||||||
// MMSize displaySize = getMainDisplaySize();
|
|
||||||
// w = displaySize.width;
|
|
||||||
// h = displaySize.height;
|
|
||||||
// }
|
|
||||||
MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h));
|
|
||||||
// printf("%s\n", bitmap);
|
// printf("%s\n", bitmap);
|
||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ MMSizeInt32 getMainDisplaySize(void){
|
|||||||
MMRectInt32 getScreenRect(int32_t display_id) {
|
MMRectInt32 getScreenRect(int32_t display_id) {
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
|
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
|
||||||
if (display_id == 0) {
|
if (display_id == -1) {
|
||||||
displayID = CGMainDisplayID();
|
displayID = CGMainDisplayID();
|
||||||
}
|
}
|
||||||
CGRect displayRect = CGDisplayBounds(displayID);
|
CGRect displayRect = CGDisplayBounds(displayID);
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
#define SCREENGRAB_H
|
#define SCREENGRAB_H
|
||||||
|
|
||||||
#include "../base/types.h"
|
#include "../base/types.h"
|
||||||
#include "../base/MMBitmap_c.h"
|
// #include "../base/MMBitmap_c.h"
|
||||||
|
#include "../base/bitmap_free_c.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -12,7 +13,7 @@ extern "C"
|
|||||||
|
|
||||||
/* Returns a raw bitmap of screengrab of the display (to be destroyed()'d by
|
/* Returns a raw bitmap of screengrab of the display (to be destroyed()'d by
|
||||||
* caller), or NULL on error. */
|
* caller), or NULL on error. */
|
||||||
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect);
|
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -17,22 +17,24 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
|
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id){
|
||||||
#if defined(IS_MACOSX)
|
#if defined(IS_MACOSX)
|
||||||
|
|
||||||
MMBitmapRef bitmap = NULL;
|
MMBitmapRef bitmap = NULL;
|
||||||
uint8_t *buffer = NULL;
|
uint8_t *buffer = NULL;
|
||||||
size_t bufferSize = 0;
|
size_t bufferSize = 0;
|
||||||
|
|
||||||
CGDirectDisplayID displayID = CGMainDisplayID();
|
CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
|
||||||
|
|
||||||
|
if (displayID == -1) {
|
||||||
|
displayID = CGMainDisplayID();
|
||||||
|
}
|
||||||
|
|
||||||
CGImageRef image = CGDisplayCreateImageForRect(displayID,
|
CGImageRef image = CGDisplayCreateImageForRect(displayID,
|
||||||
CGRectMake(rect.origin.x, rect.origin.y, rect.size.w, rect.size.h));
|
CGRectMake(rect.origin.x, rect.origin.y, rect.size.w, rect.size.h));
|
||||||
|
|
||||||
if (!image) { return NULL; }
|
if (!image) { return NULL; }
|
||||||
|
|
||||||
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
|
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
|
||||||
|
|
||||||
if (!imageData) { return NULL; }
|
if (!imageData) { return NULL; }
|
||||||
|
|
||||||
bufferSize = CFDataGetLength(imageData);
|
bufferSize = CFDataGetLength(imageData);
|
||||||
@ -40,7 +42,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
|
|||||||
|
|
||||||
CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);
|
CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);
|
||||||
|
|
||||||
bitmap = createMMBitmap(buffer,
|
bitmap = createMMBitmap_c(buffer,
|
||||||
CGImageGetWidth(image),CGImageGetHeight(image),
|
CGImageGetWidth(image),CGImageGetHeight(image),
|
||||||
CGImageGetBytesPerRow(image), CGImageGetBitsPerPixel(image),
|
CGImageGetBytesPerRow(image), CGImageGetBitsPerPixel(image),
|
||||||
CGImageGetBitsPerPixel(image) / 8);
|
CGImageGetBitsPerPixel(image) / 8);
|
||||||
@ -60,7 +62,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
|
|||||||
XCloseDisplay(display);
|
XCloseDisplay(display);
|
||||||
if (image == NULL) { return NULL; }
|
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,
|
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);
|
(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
|
image->data = NULL; /* Steal ownership of bitmap data so we don't have to
|
||||||
@ -109,7 +111,7 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect){
|
|||||||
return NULL;
|
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);
|
(uint8_t)bi.bmiHeader.biBitCount, 4);
|
||||||
|
|
||||||
/* Copy the data to our pixel buffer. */
|
/* Copy the data to our pixel buffer. */
|
||||||
|
Loading…
Reference in New Issue
Block a user