Skip to content

Commit

Permalink
Add examples code and update robotgo
Browse files Browse the repository at this point in the history
  • Loading branch information
vcaesar committed Feb 9, 2022
1 parent d070bfa commit a8e2adb
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 119 deletions.
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,38 @@
# bitmap
# bitmap

## Use

```Go
package main

import (
"fmt"

"github.com/go-vgo/robotgo"
"github.com/vcaesar/bitmap"
)

func main() {
bit := robotgo.CaptureScreen(10, 20, 30, 40)
// use `defer robotgo.FreeBitmap(bit)` to free the bitmap
defer robotgo.FreeBitmap(bit)

fmt.Println("bitmap...", bit)
img := robotgo.ToImage(bit)
// robotgo.SavePng(img, "test_1.png")
robotgo.Save(img, "test_1.png")

bit2 := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))
fx, fy := bitmap.Find(bit2)
fmt.Println("FindBitmap------ ", fx, fy)
robotgo.Move(fx, fy)

arr := bitmap.FindAll(bit2)
fmt.Println("Find all bitmap: ", arr)

fx, fy = bitmap.Find(bit)
fmt.Println("FindBitmap------ ", fx, fy)

bitmap.Save(bit, "test.png")
}
```
26 changes: 11 additions & 15 deletions base/MMBitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ extern "C"
#endif

struct _MMBitmap {
uint8_t *imageBuffer; /* Pixels stored in Quad I format; i.e., origin is in
* top left. Length should be height * bytewidth. */
size_t width; /* Never 0, unless image is NULL. */
size_t height; /* Never 0, unless image is NULL. */
size_t bytewidth; /* The aligned width (width + padding). */
uint8_t *imageBuffer; /* Pixels stored in Quad I format; i.e., origin is in top left. Length should be height * bytewidth. */
int32_t width; /* Never 0, unless image is NULL. */
int32_t height; /* Never 0, unless image is NULL. */
int32_t bytewidth; /* The aligned width (width + padding). */
uint8_t bitsPerPixel; /* Should be either 24 or 32. */
uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */
};
Expand All @@ -33,9 +32,8 @@ typedef MMBitmap *MMBitmapRef;

/* Creates new MMBitmap with the given values.
* Follows the Create Rule (caller is responsible for destroy()'ing object). */
MMBitmapRef createMMBitmap(uint8_t *buffer, size_t width, size_t height,
size_t bytewidth, uint8_t bitsPerPixel,
uint8_t bytesPerPixel);
MMBitmapRef createMMBitmap(uint8_t *buffer, int32_t width, int32_t height,
int32_t bytewidth, uint8_t bitsPerPixel, uint8_t bytesPerPixel);

// /* Releases memory occupied by MMBitmap. */
// void destroyMMBitmap(MMBitmapRef bitmap);
Expand All @@ -50,8 +48,8 @@ MMBitmapRef copyMMBitmap(MMBitmapRef bitmap);
* by the caller.), or NULL on error. */
MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect);

#define MMBitmapPointInBounds(image, p) ((p).x < (image)->width && \
(p).y < (image)->height)
#define MMBitmapPointInBounds(image, p) ((p).x < (image)->width && (p).y < (image)->height)

#define MMBitmapRectInBounds(image, r) \
(((r).origin.x + (r).size.width <= (image)->width) && \
((r).origin.y + (r).size.height <= (image)->height))
Expand All @@ -61,16 +59,14 @@ MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect);
/* Get pointer to pixel of MMBitmapRef. No bounds checking is performed (check
* yourself before calling this with MMBitmapPointInBounds(). */
#define MMRGBColorRefAtPoint(image, x, y) \
(MMRGBColor *)(assert(MMBitmapPointInBounds(image, MMPointMake(x, y))), \
((image)->imageBuffer) + (((image)->bytewidth * (y)) \
+ ((x) * (image)->bytesPerPixel)))
(MMRGBColor *)(assert(MMBitmapPointInBounds(image, MMPointMake(x, y))), \
((image)->imageBuffer) + (((image)->bytewidth * (y)) + ((x) * (image)->bytesPerPixel)))

/* Dereference pixel of MMBitmapRef. Again, no bounds checking is performed. */
#define MMRGBColorAtPoint(image, x, y) *MMRGBColorRefAtPoint(image, x, y)

/* Hex/integer value of color at point. */
#define MMRGBHexAtPoint(image, x, y) \
hexFromMMRGB(MMRGBColorAtPoint(image, x, y))
#define MMRGBHexAtPoint(image, x, y) hexFromMMRGB(MMRGBColorAtPoint(image, x, y))

/* Increment either point.x or point.y depending on the position of point.x.
* That is, if x + 1 is >= width, increment y and start x at the beginning.
Expand Down
31 changes: 9 additions & 22 deletions base/bitmap/MMBitmap_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@
#include <assert.h>
#include <string.h>

MMBitmapRef createMMBitmap(
uint8_t *buffer,
size_t width,
size_t height,
size_t bytewidth,
uint8_t bitsPerPixel,
uint8_t bytesPerPixel
){
MMBitmapRef createMMBitmap(uint8_t *buffer, int32_t width, int32_t height,
int32_t bytewidth, uint8_t bitsPerPixel, uint8_t bytesPerPixel
) {
MMBitmapRef bitmap = malloc(sizeof(MMBitmap));
if (bitmap == NULL) return NULL;

Expand All @@ -30,17 +25,13 @@ MMBitmapRef copyMMBitmap(MMBitmapRef bitmap) {
if (bitmap->imageBuffer != NULL) {
const size_t bufsize = bitmap->height * bitmap->bytewidth;
copiedBuf = malloc(bufsize);
if (copiedBuf == NULL) return NULL;
if (copiedBuf == NULL) { return NULL; }

memcpy(copiedBuf, bitmap->imageBuffer, bufsize);
}

return createMMBitmap(copiedBuf,
bitmap->width,
bitmap->height,
bitmap->bytewidth,
bitmap->bitsPerPixel,
bitmap->bytesPerPixel);
return createMMBitmap(copiedBuf, bitmap->width, bitmap->height,
bitmap->bytewidth, bitmap->bitsPerPixel, bitmap->bytesPerPixel);
}

MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect) {
Expand All @@ -58,15 +49,11 @@ MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect) {
assert((bufsize + offset) <= (source->bytewidth * source->height));

copiedBuf = malloc(bufsize);
if (copiedBuf == NULL) return NULL;
if (copiedBuf == NULL) { return NULL; }

memcpy(copiedBuf, source->imageBuffer + offset, bufsize);

return createMMBitmap(copiedBuf,
rect.size.width,
rect.size.height,
source->bytewidth,
source->bitsPerPixel,
source->bytesPerPixel);
return createMMBitmap(copiedBuf, rect.size.width, rect.size.height,
source->bytewidth, source->bitsPerPixel, source->bytesPerPixel);
}
}
43 changes: 13 additions & 30 deletions base/bitmap/str_io_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@
#define STR_BITS_PER_PIXEL 24
#define STR_BYTES_PER_PIXEL ((STR_BITS_PER_PIXEL) / 8)

#define MAX_DIMENSION_LEN 5 /* Maximum length for [width] or [height]
* in string. */
#define MAX_DIMENSION_LEN 5 /* Maximum length for [width] or [height] in string. */

const char *MMBitmapStringErrorString(MMBMPStringError err)
{
const char *MMBitmapStringErrorString(MMBMPStringError err) {
switch (err) {
case kMMBMPStringInvalidHeaderError:
return "Invalid header for string";
Expand All @@ -46,19 +44,14 @@ const char *MMBitmapStringErrorString(MMBMPStringError err)
* |len| is set to the length of [width] + the length of [height] + 2,
* and true is returned; otherwise, false is returned.
*/
static bool getSizeFromString(const uint8_t *buf, size_t buflen,
size_t *width, size_t *height,
size_t *len);
static bool getSizeFromString(const uint8_t *buf, size_t buflen, size_t *width, size_t *height, size_t *len);

MMBitmapRef createMMBitmapFromString(const uint8_t *buffer, size_t buflen,
MMBMPStringError *err)
{
MMBitmapRef createMMBitmapFromString(const uint8_t *buffer, size_t buflen, MMBMPStringError *err) {
uint8_t *decoded, *decompressed;
size_t width, height;
size_t len, bytewidth;

if (*buffer++ != 'b' || !getSizeFromString(buffer, --buflen,
&width, &height, &len)) {
if (*buffer++ != 'b' || !getSizeFromString(buffer, --buflen, &width, &height, &len)) {
if (err != NULL) *err = kMMBMPStringInvalidHeaderError;
return NULL;
}
Expand Down Expand Up @@ -96,8 +89,7 @@ MMBitmapRef createMMBitmapFromString(const uint8_t *buffer, size_t buflen,
* Caller is responsible for free()'ing returned buffer. */
static uint8_t *createRawBitmapData(MMBitmapRef bitmap);

uint8_t *createStringFromMMBitmap(MMBitmapRef bitmap, MMBMPStringError *err)
{
uint8_t *createStringFromMMBitmap(MMBitmapRef bitmap, MMBMPStringError *err) {
uint8_t *raw, *compressed;
uint8_t *ret, *encoded;
size_t len, retlen;
Expand All @@ -110,10 +102,7 @@ uint8_t *createStringFromMMBitmap(MMBitmapRef bitmap, MMBMPStringError *err)
return NULL;
}

compressed = zlib_compress(raw,
bitmap->width * bitmap->height *
STR_BYTES_PER_PIXEL,
9, &len);
compressed = zlib_compress(raw, bitmap->width * bitmap->height * STR_BYTES_PER_PIXEL, 9, &len);
free(raw);
if (compressed == NULL) {
if (err != NULL) *err = kMMBMPStringCompressError;
Expand All @@ -130,20 +119,16 @@ uint8_t *createStringFromMMBitmap(MMBitmapRef bitmap, MMBMPStringError *err)
retlen += 3 + (MAX_DIMENSION_LEN * 2);
ret = calloc(sizeof(char), (retlen + 1));
snprintf((char *)ret, retlen, "b%lu,%lu,%s", (unsigned long)bitmap->width,
(unsigned long)bitmap->height,
encoded);
(unsigned long)bitmap->height, encoded);
ret[retlen] = '\0';
free(encoded);
return ret;
}

static uint32_t parseDimension(const uint8_t *buf, size_t buflen,
size_t *numlen);
static uint32_t parseDimension(const uint8_t *buf, size_t buflen, size_t *numlen);

static bool getSizeFromString(const uint8_t *buf, size_t buflen,
size_t *width, size_t *height,
size_t *len)
{
static bool getSizeFromString(const uint8_t *buf, size_t buflen,
size_t *width, size_t *height, size_t *len) {
size_t numlen;
assert(buf != NULL);
assert(width != NULL);
Expand All @@ -164,8 +149,7 @@ static bool getSizeFromString(const uint8_t *buf, size_t buflen,

/* Parses one dimension from string as described in getSizeFromString().
* Returns dimension on success, or 0 on error. */
static uint32_t parseDimension(const uint8_t *buf,
size_t buflen, size_t *numlen){
static uint32_t parseDimension(const uint8_t *buf, size_t buflen, size_t *numlen) {
char num[MAX_DIMENSION_LEN + 1];
size_t i;
// ssize_t len;
Expand All @@ -184,8 +168,7 @@ static uint32_t parseDimension(const uint8_t *buf,
return (uint32_t)atoi(num);
}

static uint8_t *createRawBitmapData(MMBitmapRef bitmap)
{
static uint8_t *createRawBitmapData(MMBitmapRef bitmap) {
uint8_t *raw = calloc(STR_BYTES_PER_PIXEL, bitmap->width * bitmap->height);
size_t y;

Expand Down
3 changes: 1 addition & 2 deletions base/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
/* Python versions under 2.5 don't support this macro, but it's not
* terribly difficult to replicate: */
#ifndef PyModule_AddIntMacro
#define PyModule_AddIntMacro(module, macro) \
PyModule_AddIntConstant(module, #macro, macro)
#define PyModule_AddIntMacro(module, macro) PyModule_AddIntConstant(module, #macro, macro)
#endif /* PyModule_AddIntMacro */

#if !defined(IS_MACOSX) && defined(__APPLE__) && defined(__MACH__)
Expand Down
15 changes: 4 additions & 11 deletions base/rgb.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <stdint.h>
#endif


/* RGB colors in MMBitmaps are stored as BGR for convenience in converting
* to/from certain formats (mainly OpenGL).
*
Expand Down Expand Up @@ -46,8 +45,7 @@ typedef uint32_t MMRGBHex;
#define RGB_TO_HEX(red, green, blue) (((red) << 16) | ((green) << 8) | (blue))

/* Convenience wrapper for MMRGBColors. */
H_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb)
{
H_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb) {
return RGB_TO_HEX(rgb.red, rgb.green, rgb.blue);
}

Expand All @@ -56,8 +54,7 @@ H_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb)
#define BLUE_FROM_HEX(hex) (hex & 0xFF)

/* Converts hexadecimal color to MMRGBColor. */
H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex)
{
H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex) {
MMRGBColor color;
color.red = RED_FROM_HEX(hex);
color.green = GREEN_FROM_HEX(hex);
Expand All @@ -73,9 +70,7 @@ H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex)
/* Returns whether two colors are similar within the given range, |tolerance|.
* Tolerance can be in the range 0.0f - 1.0f, where 0 denotes the exact
* color and 1 denotes any color. */
H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2,
float tolerance)
{
H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2, float tolerance) {
/* Speedy case */
if (tolerance <= 0.0f) {
return MMRGBColorEqualToColor(c1, c2);
Expand All @@ -87,12 +82,10 @@ H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2,
(d2 * d2) +
(d3 * d3)) <= (tolerance * 442.0f);
}

}

/* Identical to MMRGBColorSimilarToColor, only for hex values. */
H_INLINE int MMRGBHexSimilarToColor(MMRGBHex h1, MMRGBHex h2, float tolerance)
{
H_INLINE int MMRGBHexSimilarToColor(MMRGBHex h1, MMRGBHex h2, float tolerance) {
if (tolerance <= 0.0f) {
return h1 == h2;
} else {
Expand Down
15 changes: 10 additions & 5 deletions bitmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ func ToRobot(bit C.MMBitmapRef) robotgo.CBitmap {
func ToC(bit robotgo.Bitmap) C.MMBitmapRef {
cbitmap := C.createMMBitmap(
(*C.uint8_t)(bit.ImgBuf),
C.size_t(bit.Width),
C.size_t(bit.Height),
C.size_t(bit.Bytewidth),
C.int32_t(bit.Width),
C.int32_t(bit.Height),
C.int32_t(bit.Bytewidth),
C.uint8_t(bit.BitsPixel),
C.uint8_t(bit.BytesPerPixel),
)
Expand Down Expand Up @@ -289,15 +289,20 @@ func Open(path string, args ...int) robotgo.CBitmap {
return ToRobot(OpenC(path, args...))
}

// FromStr bitmap from string
func FromStr(str string) C.MMBitmapRef {
// FromStrC bitmap from string
func FromStrC(str string) C.MMBitmapRef {
cs := C.CString(str)
bit := C.bitmap_from_string(cs)
C.free(unsafe.Pointer(cs))

return bit
}

// FromStr bitmap from string
func FromStr(str string) robotgo.CBitmap {
return ToRobot(FromStrC(str))
}

func toErr(str *C.char) error {
gstr := C.GoString(str)
if gstr == "" {
Expand Down
Loading

0 comments on commit a8e2adb

Please sign in to comment.