[OSX] Screenshot

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

 

Macintosh

Betreff: [OSX] Screenshot

BeitragMi, Okt 06, 2010 11:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey.
Ich habe gestern aus langer weile bissle an ner funktin rumgefummelt, das man screenshots machen kann, und diese dann als pixmap hat.

Die funktion hat allerdings noch Fehler, und ist nicht grade "sauber gecodet", so lässt sich mit dem Pixmap auser es zu zeichnen fast nichts machen.

screenshot.m
Code: [AUSKLAPPEN]

#import <AppKit/AppKit.h>

typedef struct bbpixmap bbpixmap;

struct bbpixmap{
   void      *class;
   int      refs;
   unsigned char *pixels;
   int      width,height,pitch,format,capacity;
};

const static char BytesPerPixel[]={0,1,1,3,3,4,4};

bbpixmap * BBPixmapWithCGImage(CGImageRef image, int format, int align)
{
   NSBitmapImageRep * bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
   struct bbpixmap * pixmap;
   
   int bytesPerPixel, bitsPerPixel, bytesPerRow;
   int height, width;
   unsigned char * data;
   
   BOOL alpha = NO;
   bytesPerPixel = [bitmap samplesPerPixel];
   bitsPerPixel = [bitmap bitsPerPixel];
   bytesPerRow = [bitmap bytesPerRow];
   height = CGImageGetHeight(image);
   width = CGImageGetWidth(image);
   data = [bitmap bitmapData];

   pixmap->width = width;
   pixmap->height = height;
   pixmap->format = format;
   pixmap->pitch = (width*BytesPerPixel[format]+(align-1))/align*align;
   pixmap->capacity = pixmap->pitch*height;
   pixmap->pixels = malloc(pixmap->capacity);
   
   int i;
   for (i = 0; i < height; i++)
   {
      memcpy(pixmap->pixels + (i*pixmap->pitch), data + (i*bytesPerRow+1), bytesPerRow);
   }
   
   [bitmap release];
   CGImageRelease(image);
   
   return pixmap;
}

bbpixmap * captureScreen( int a )
{
   CGImageRef image = CGDisplayCreateImage(CGMainDisplayID());
   return BBPixmapWithCGImage(image, 6, a);
}

bbpixmap * captureScreenRect( float x, float y, float w, float h )
{
   CGRect rect;
      rect.origin.x = x;
      rect.origin.y = y;
      rect.size.width = w;
      rect.size.height = h;
   CGImageRef image = CGDisplayCreateImageForRect(CGMainDisplayID(), rect);
   return BBPixmapWithCGImage(image, 6, 4);
}

void freePixmap(bbpixmap * pixmap)
{
   pixmap->refs = 0;
   free(pixmap->pixels);
   pixmap->width = 0;
   pixmap->height = 0;
   pixmap->pitch = 0;
   pixmap->format = 0;
   pixmap->capacity = 0;
}


screenshot.bmx
BlitzMax: [AUSKLAPPEN]

Import "screenshot.m"

Extern
Function captureScreen:TPixmap(align_bytes:Int=4)
'Function captureScreenRect:TPixmap(x:Float, y:Float, w:Float, h:Float) 'geht nicht!
Function freePixmap(p:TPixmap)
EndExtern

Local p:TPixmap
p = captureScreen()

Graphics 1680, 1050,32

Repeat

DrawPixmap(p,0,0)
WaitKey

Flip ; Cls
Until AppTerminate()
End



viel spaß.
Vieleicht hat ja jemand lust das zu verbessern, sodas es ordentlich funktioniert :)
 

joasia36

BeitragMo, Sep 05, 2011 22:01
Antworten mit Zitat
Benutzer-Profile anzeigen
ich versteh zwar nicht warum, aber bei mir crashed der c-code beim ersten zugriff auf die bbpixmap:

pixmap->width = width;

hat irgendjemand eine Idee?

d-bug

BeitragDi, Sep 06, 2011 18:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo joasia36,

ich nehme mal an du hast bereits Lion, oder?

Während unter Snow-Leopard Macintoshs Code noch ohne Probleme lief, wird unter Lion einfach keine Instanz des structs bbpixmap erstellt. Weil es diese nicht gibt, stürzt die Applikation eben kommentarlos ab, wenn das erste mal darauf zugegriffen werden soll.

Folgende kleine Änderung sollte dir weiter helfen:

Code: [AUSKLAPPEN]

#import <AppKit/AppKit.h>

typedef struct bbpixmap bbpixmap;

struct bbpixmap{
    void      *class;
    int      refs;
    unsigned char *pixels;
    int      width,height,pitch,format,capacity;
};

const static char BytesPerPixel[]={0,1,1,3,3,4,4};

bbpixmap * BBPixmapWithCGImage(bbpixmap *pixmap, CGImageRef image, int format, int align)
{
    NSBitmapImageRep * bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
   
    int bytesPerPixel, bitsPerPixel, bytesPerRow;
    int height, width;
    unsigned char * data;
   
    BOOL alpha = NO;
    bytesPerPixel = [bitmap samplesPerPixel];
    bitsPerPixel = [bitmap bitsPerPixel];
    bytesPerRow = [bitmap bytesPerRow];
    height = CGImageGetHeight(image);
    width = CGImageGetWidth(image);
    data = [bitmap bitmapData];
   
    pixmap->width = width;
    pixmap->height = height;
    pixmap->format = format;
    pixmap->pitch = (width*BytesPerPixel[format]+(align-1))/align*align;
    pixmap->capacity = pixmap->pitch*height;
    pixmap->pixels = malloc(pixmap->capacity);
   
    int i;
    for (i = 0; i < height; i++)
    {
        memcpy(pixmap->pixels + (i*pixmap->pitch), data + (i*bytesPerRow+1), bytesPerRow);
    }
   
    [bitmap release];
    CGImageRelease(image);
   
    return pixmap;
}

bbpixmap * captureScreen(bbpixmap *pixmap, int a )
{
    CGImageRef image = CGDisplayCreateImage(CGMainDisplayID());
    return BBPixmapWithCGImage(pixmap, image, 6, a);
}

bbpixmap * captureScreenRect(bbpixmap *pixmap, float x, float y, float w, float h )
{
    CGRect rect;
    rect.origin.x = x;
    rect.origin.y = y;
    rect.size.width = w;
    rect.size.height = h;
    CGImageRef image = CGDisplayCreateImageForRect(CGMainDisplayID(), rect);
    return BBPixmapWithCGImage(pixmap, image, 6, 4);
}

void freePixmap(bbpixmap * pixmap)
{
    pixmap->refs = 0;
    free(pixmap->pixels);
    pixmap->width = 0;
    pixmap->height = 0;
    pixmap->pitch = 0;
    pixmap->format = 0;
    pixmap->capacity = 0;
}


...und damit man auch was sehen kann:
BlitzMax: [AUSKLAPPEN]
Import "screenshot.m"

Extern
Function captureScreen:TPixmap(pixmap:TPixmap, align_bytes:Int=4)
'Function captureScreenRect:TPixmap(x:Float, y:Float, w:Float, h:Float) 'geht nicht!
Function freePixmap(p:TPixmap)
EndExtern

Local p:TPixmap
p = captureScreen((New TPixmap))

Graphics 640, 480,0

Repeat

DrawPixmap(p,0,0)
'WaitKey

Flip ; Cls
Until AppTerminate()
End


Ich habe in dieser kleinen Änderung lediglich dafür gesorgt, dass BlitzMax eine fertige Instanz von TPixmap an Objektive-C übergibt, die Objektive-C nur noch ausfüllen braucht. So funktionierst dann auch unter Lion wieder.
Es gibt bestimmt auch einen eleganteren Fix dafür, allerdings hab ich zu wenig Ahnung von structs um das geschmeidiger zu lösen.

@Macintosh: Verzeih meine Einmischung. Wink
 

joasia36

BeitragDi, Sep 06, 2011 22:27
Antworten mit Zitat
Benutzer-Profile anzeigen
ja, danke, hatte den Fehler auch inzwischen gefunden.
Habe das Problem allerdings über einen malloc gelöst. Sind noch zwei ganz nette Funktionen hinzugekommen; falls Interesse besteht:

Code: [AUSKLAPPEN]
#import <AppKit/AppKit.h>

typedef struct bbpixmap{
   void            *class;
   int            refs;
   unsigned char      *pixels;
   int            width, height, pitch, format, capacity;
} bbpixmap;

const static char BytesPerPixel[]={0,1,1,3,3,4,4};

bbpixmap *BBPixmapWithCGImage(CGImageRef image, int format, int align)
{
   NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
   bbpixmap *pixmap;
   pixmap = malloc(sizeof(bbpixmap));

   int bytesPerPixel, bitsPerPixel, bytesPerRow;
   int height, width;
   unsigned char *data;

   BOOL alpha = NO;
   bytesPerPixel = [bitmap samplesPerPixel];
   bitsPerPixel = [bitmap bitsPerPixel];
   bytesPerRow = [bitmap bytesPerRow];
   height = CGImageGetHeight(image);
   width = CGImageGetWidth(image);
   data = [bitmap bitmapData];

   pixmap->width = width;
   pixmap->height = height;
   pixmap->format = format;
   pixmap->pitch = (width*BytesPerPixel[format]+(align-1))/align*align;
   pixmap->capacity = pixmap->pitch*height;
   pixmap->pixels = malloc(pixmap->capacity);

   int i;
   for (i = 0; i < height; i++)
   {
      memcpy(pixmap->pixels + (i*pixmap->pitch), data + (i*bytesPerRow+1), bytesPerRow);
   }

   [bitmap release];
   CGImageRelease(image);
   return pixmap;
}

void freePixmap(bbpixmap *pixmap)
{
   free(pixmap->pixels);
   free(pixmap);
}

bbpixmap *pixmapWithScreen(int a)
{
   CGImageRef image = CGDisplayCreateImage(CGMainDisplayID());
   return BBPixmapWithCGImage(image, 6, a);
}

bbpixmap *pixmapWithScreenRect(float x, float y, float w, float h)
{
   CGRect rect = CGRectMake(x, y, w, h);
   CGImageRef image = CGDisplayCreateImageForRect(CGMainDisplayID(), rect);
   return BBPixmapWithCGImage(image, 6, 4);
}

bbpixmap *NSPixmapWithWindow(NSWindow *window)
{
   CGWindowID windowID = [window windowNumber];
   CGImageRef windowImage = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageBoundsIgnoreFraming);
   
   if(CGImageGetWidth(windowImage) <= 1) {
      CGImageRelease(windowImage);
      return nil;
   }
   return BBPixmapWithCGImage(windowImage, 6, 4); 
}

bbpixmap *NSPixmapBelowWindow(NSWindow *window)

   CGWindowID windowID = [window windowNumber];
   
   CGRect windowRect = NSRectToCGRect( [window frame] );
   windowRect.origin.y = NSMaxY([[window screen] frame]) - NSMaxY([window frame]);
       
   CGImageRef capturedImage = CGWindowListCreateImage( windowRect, kCGWindowListOptionOnScreenBelowWindow, windowID, kCGWindowImageDefault );

   if(CGImageGetWidth(capturedImage) <= 1) {
      CGImageRelease(capturedImage);
      return nil;
   }
   return BBPixmapWithCGImage(capturedImage, 6, 4);
}


und dann noch:

Code: [AUSKLAPPEN]
Import "screenshot.m"
Import MaxGui.Drivers

Extern
   Function pixmapWithScreen:TPixmap(align_bytes:Int=4)
   Function pixmapWithScreenRect:TPixmap(x:Float, y:Float, w:Float, h:Float) 'geht!
   Function NSPixmapWithWindow:TPixmap(NSWindow)
   Function NSPixmapBelowWindow:TPixmap(NSWindow)
   Function freePixmap(p:TPixmap)
End Extern

Function pixmapWithWindow:TPixmap(window:TGadget)
   Local NSWindow = QueryGadget(window, QUERY_NSVIEW)
   If GadgetClass(window) = GADGET_WINDOW And NSWindow Return NSPixmapWithWindow(NSWindow)
End Function

Function pixmapBelowWindow:TPixmap(window:TGadget)
   Local NSWindow = QueryGadget(window, QUERY_NSVIEW)
   If GadgetClass(window) = GADGET_WINDOW And NSWindow Return NSPixmapBelowWindow(NSWindow)
End Function

Local window:TGadget = CreateWindow( AppTitle, 100, 100, 320, 240, Null, WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_STATUS)
SetStatusText( window, "hello world! - press any key to continue..." )
While Not ActiveGadget(); Wend ' wait for the window to appear

Local a:TPixmap = pixmapWithScreen()
Local b:TPixmap = pixmapWithScreenRect(1000,0,440,250)
Local c:TPixmap = pixmapWithWindow(window)
Local d:TPixmap = pixmapBelowWindow(window)

Graphics 1440, 900,32
SetBlend ALPHABLEND
SetAlpha 0.2
SetColor 0,0,0
DrawPixmap(a,0,0); freepixmap(a)
DrawRect 40,250,300,30
DrawRect 590,120,PixmapWidth(b)+20,PixmapHeight(b)+40
DrawRect 40,440,PixmapWidth(c )+20,PixmapHeight(c )+40
DrawRect 590,440,PixmapWidth(d)+20,PixmapHeight(d)+40
SetAlpha 1
DrawText "captureScreen()",50,255
DrawText "captureScreenRect()",600,125
DrawText "imageWithWindow()",50,445
DrawText "imageBelowWindow()",600,445
DrawPixmap(b,600,150); freepixmap(b)
DrawPixmap(c,50,470); freepixmap(c )
DrawPixmap(d,600,470); freepixmap(d)
Flip

WaitKey


Sorry wegen der Änderung der Funktionsnamen, erschien mir so allerdings stimmiger. Könnte man schon fast ein Modul raus machen.
BTW: in welchem Header sind eigentlich bbpixmap und BytesPerPixel deklariert (include/import scheint mir hier sinnvoll?).

Die beiden zusätzlichen Funktionen habe ich mir übrigens hier abgeschaut: http://www.cocoadev.com/index.pl?ScreenShotCode
 

Macintosh

BeitragFr, Okt 14, 2011 21:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Höhö das ja schon ein weilchen her..
da konnte ich noch garkein C, also nicht so richtig ^^
Aber freut mich das der code interessiert :)

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group