⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 screenscraphelper.mm

📁 lumaqq
💻 MM
字号:
/* * LumaQQ - Cross platform QQ client, special edition for Mac * * Copyright (C) 2007 luma <stubma@163.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#import "ScreenscrapHelper.h"#import "GrabView.h"#import "AnimationHelper.h"#import "Constants.h"#import <OpenGL/OpenGL.h>#import <OpenGL/gl.h>#define SWAP_PIXEL(p) (((p) << 8) | ((p) >> 24))static ScreenscrapHelper* s_helper = nil;@implementation BorderlessKeyWindow- (BOOL)canBecomeKeyWindow {	return YES;}@end@implementation ScreenscrapHelperstatic inline void swapcopy32(void * src, void * dst, int bytecount) {    uint32_t *srcP;    uint32_t *dstP;    uint32_t p0, p1, p2, p3;    uint32_t u0, u1, u2, u3;        srcP = (uint32_t*)src;    dstP = (uint32_t*)dst;	    while(bytecount >= 16) {        /*         * Blatent hint to compiler that we want         * strength reduction, pipelined fetches, and         * some instruction scheduling, please.         */        p3 = srcP[3];        p2 = srcP[2];        p1 = srcP[1];        p0 = srcP[0];                u3 = SWAP_PIXEL(p3);        u2 = SWAP_PIXEL(p2);        u1 = SWAP_PIXEL(p1);        u0 = SWAP_PIXEL(p0);        srcP += 4;				// must take care byte order in intel mac        dstP[3] = EndianU32_NtoB(u3);        dstP[2] = EndianU32_NtoB(u2);        dstP[1] = EndianU32_NtoB(u1);        dstP[0] = EndianU32_NtoB(u0);        bytecount -= 16;        dstP += 4;    }    while(bytecount >= 4) {        p0 = *srcP++;        bytecount -= 4;        *dstP++ = EndianU32_NtoB(SWAP_PIXEL(p0));    }}- (void)swizzleBitmap:(NSBitmapImageRep*)bitmap {	    int rowBytes = [bitmap bytesPerRow];    int top = 0;    int bottom = [bitmap pixelsHigh] - 1;    void* base = [bitmap bitmapData];    void* buffer = malloc(rowBytes);        while(top < bottom) {        void* topP = (top * rowBytes) + (char*)base;        void* bottomP = (bottom * rowBytes) + (char*)base;                /* Save and swap scanlines */        swapcopy32( topP, buffer, rowBytes );        swapcopy32( bottomP, topP, rowBytes );        bcopy( buffer, bottomP, rowBytes );                ++top;        --bottom;    }    free(buffer);}- (NSData*)captureRect:(NSRect)rect {	/* Build a full-screen GL context */	CGLContextObj glContextObj;	CGLPixelFormatObj pixelFormatObj;	long numPixelFormats;	CGOpenGLDisplayMask displayMask = CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID());	CGLPixelFormatAttribute attribs[] = {		kCGLPFAFullScreen,		kCGLPFADisplayMask,		(CGLPixelFormatAttribute)displayMask,		(CGLPixelFormatAttribute)NULL	};		CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats);	CGLCreateContext(pixelFormatObj, NULL, &glContextObj);	CGLDestroyPixelFormat(pixelFormatObj);	CGLSetCurrentContext(glContextObj);	CGLSetFullScreen(glContextObj);	    /* Get OpenGL aimed at FB */    CGLSetCurrentContext(glContextObj);		GLint width = NSWidth(rect);	GLint height = NSHeight(rect);	    long bytewidth = width * 4;	// Assume 4 bytes/pixel for now    bytewidth = (bytewidth + 3) & ~3;	// Align to 4 bytes        /* Build NSBitmapImageRep */    NSBitmapImageRep* rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL																	 pixelsWide:width																	 pixelsHigh:height																  bitsPerSample:8																samplesPerPixel:3																	   hasAlpha:NO																	   isPlanar:NO																 colorSpaceName:NSDeviceRGBColorSpace																	bytesPerRow:bytewidth																   bitsPerPixel:(8 * 4)] autorelease];	    /* Read FB into NSBitmapImageRep */    glFinish();				/* Finish all OpenGL commands */    glPixelStorei(GL_PACK_ALIGNMENT, 4);	/* Force 4-byte alignment */    glPixelStorei(GL_PACK_ROW_LENGTH, 0);    glPixelStorei(GL_PACK_SKIP_ROWS, 0);    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);	    /*     * By matching the framebuffer format, we can get the     * data transferred to our buffer using DMA.     */    glReadPixels(NSMinX(rect), 				 NSMinY(rect), 				 width, 				 height,				 GL_BGRA,				 GL_UNSIGNED_INT_8_8_8_8_REV,				 [rep bitmapData]);	    /*     * glReadPixels generates a quadrant I raster, with origin in the lower left     * This isn't a problem for signal processing routines such as compressors,     * as they can simply use a negative 'adavnce' to move between scanlines.     * NSBitmapImageRep assumes a quadrant III raster, though, so we need to     * invert it.  Pixel swizzling can also be done here.     */    [self swizzleBitmap:rep];		// clean	CGLSetCurrentContext(NULL);    CGLClearDrawable(glContextObj);    CGLDestroyContext(glContextObj);		// get image data	return [rep representationUsingType:NSJPEGFileType properties:nil];}+ (ScreenscrapHelper*)sharedHelper {	if(s_helper == nil)		s_helper = [[ScreenscrapHelper alloc] init];	return s_helper;}- (id) init {	self = [super init];	if (self != nil) {		m_busy = NO;				[[NSNotificationCenter defaultCenter] addObserver:self												 selector:@selector(handleScreenscrapDidFinishedNotification:)													 name:kScreenscrapDidFinishedNotificationName												   object:nil];	}	return self;}- (void) dealloc {	[[NSNotificationCenter defaultCenter] removeObserver:self													name:kScreenscrapDidFinishedNotificationName												  object:nil];	[super dealloc];}- (void)windowWillClose:(NSNotification *)aNotification {	// get rect, packed as a value	NSRect rect = [[m_window contentView] scrapRect];	NSValue* value = [NSValue valueWithRect:rect];		// release window	if(m_window) {		[m_window autorelease];		m_window = nil;	}	if(m_hintWindow) {		[m_hintWindow close];		[m_hintWindow release];		m_hintWindow = nil;	}		// post notification	NSNotification* n = [NSNotification notificationWithName:kScreenscrapDidFinishedNotificationName 													  object:value];	[[NSNotificationQueue defaultQueue] enqueueNotification:n											   postingStyle:NSPostASAP];		// reset flag to accept next screenscrap	m_busy = NO;}- (void)handleScreenscrapDidFinishedNotification:(NSNotification*)notification {	// get capture rect	NSRect rect = [[notification object] rectValue];		// check rect	if(NSWidth(rect) <= 0 || NSHeight(rect) <= 0)		return;		// capture screen	NSData* data = [self captureRect:rect];		// generate a uuid as file name	CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);	NSString* uuidStr = (NSString*)CFUUIDCreateString(kCFAllocatorDefault, uuid);	CFRelease(uuid);		// write to file	NSString* path = [NSString stringWithFormat:@"/tmp/{%@}.JPG", uuidStr];	[data writeToFile:path atomically:YES];	[uuidStr release];		// post notification	NSNotification* n = [NSNotification notificationWithName:kScreenscrapDataDidPopulatedNotificationName													  object:data													userInfo:[NSDictionary dictionaryWithObject:path forKey:kUserInfoImagePath]];	[[NSNotificationQueue defaultQueue] enqueueNotification:n											   postingStyle:NSPostASAP];}- (void)beginScreenscrap {	// check flag	if(m_busy)		return;	m_busy = YES;		// get screen size	NSRect frame = [[NSScreen mainScreen] frame];		// create screenshot window    m_window = [[BorderlessKeyWindow alloc] initWithContentRect:frame 													  styleMask:NSBorderlessWindowMask														backing:NSBackingStoreBuffered														  defer:NO];	[m_window setReleasedWhenClosed:NO];	[m_window setContentView:[[[GrabView alloc] initWithFrame:frame] autorelease]];	[m_window setInitialFirstResponder:[m_window contentView]];	[m_window setDelegate:self];    [m_window setBackgroundColor:[NSColor clearColor]];    [m_window setLevel:(NSScreenSaverWindowLevel + 1)];    [m_window setHasShadow:NO];	    [m_window setAlphaValue:0];	[m_window setAcceptsMouseMovedEvents:YES];		// create hint image	NSImage* hintImage = [NSImage imageNamed:kImageScreenscrapHint];	NSSize imageSize = [hintImage size];		// calculate hint window dest frame	NSRect destFrame = NSMakeRect(50, NSMaxY(frame) - imageSize.height + 1, imageSize.width - 1, imageSize.height - 1);	NSRect hintEndFrame = destFrame;	hintEndFrame.origin.y += NSHeight(frame);		// calculate hint window start frame	NSRect hintStartFrame = destFrame;	hintStartFrame.origin.y -= NSHeight(frame);		// create hint window    m_hintWindow = [[NSWindow alloc] initWithContentRect:hintStartFrame											   styleMask:NSBorderlessWindowMask												 backing:NSBackingStoreBuffered												   defer:NO];	[m_hintWindow setReleasedWhenClosed:NO];	NSImageView* imageView = [[[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, imageSize.width - 1, imageSize.height - 1)] autorelease];	[imageView setImageFrameStyle:NSImageFrameNone];	[imageView setImage:hintImage];	[m_hintWindow setContentView:imageView];	[m_hintWindow setHasShadow:NO];	[m_hintWindow setLevel:(NSScreenSaverWindowLevel + 2)];		// set hint window to grab view	[[m_window contentView] setHintWindow:m_hintWindow];		// begin animation	[m_window orderFront:self];	[m_hintWindow orderFront:self];	[AnimationHelper moveWindow:m_hintWindow						   from:hintStartFrame							 to:hintEndFrame						 fadeIn:m_window						fadeOut:nil				   progressMark:0.5					   duration:0.75						  curve:NSAnimationLinear					   delegate:self];}#pragma mark -#pragma mark animation delegate- (void)animationDidEnd:(NSAnimation *)animation {	[m_window makeKeyWindow];}- (void)animationDidStop:(NSAnimation*)animation {	[m_window makeKeyWindow];}- (void)animation:(NSAnimation*)animation didReachProgressMark:(NSAnimationProgress)progress {	if(progress == 0.5)		[animation stopAnimation];}@end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -