Пример #1
0
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect)
{
#if defined(IS_MACOSX)
	/* The following is a very modified version of the glGrab code example
	 * given by Apple (as are some of the convenience functions called). */
	size_t bytewidth;
	uint8_t bitsPerPixel, bytesPerPixel;
	uint8_t *buffer;

	/* Build OpenGL context of entire screen */
	CGDirectDisplayID displayID = CGMainDisplayID();
	CGOpenGLDisplayMask mask = CGDisplayIDToOpenGLDisplayMask(displayID);
	CGLContextObj glContext = createFullScreenCGLContext(mask);
	if (glContext == NULL) return NULL;

	/* TODO: CGDisplayBitsPerPixel() is deprecated in Snow Leopard; I'm not
	 * sure of the replacement function. */
	bitsPerPixel = (uint8_t)CGDisplayBitsPerPixel(displayID);
	bytesPerPixel = bitsPerPixel / 8;

	/* Align width to padding. */
	bytewidth = ADD_PADDING(rect.size.width * bytesPerPixel);

	/* Convert Quartz point to postscript point. */
	rect.origin.y = CGDisplayPixelsHigh(displayID) - rect.origin.y - rect.size.height;

	/* Extract buffer from context */
	buffer = createBufferFromCurrentCGLContext((GLint)rect.origin.x,
	                                           (GLint)rect.origin.y,
	                                           (GLsizei)rect.size.width,
	                                           (GLsizei)rect.size.height,
	                                           bytewidth);
	/* Reset and release GL context */
	destroyFullScreenCGLContext(glContext);
	if (buffer == NULL) return NULL;

	/* Convert from OpenGL (origin at bottom left) to Quartz (origin at top
	 * left) coordinate system. */
	flipBitmapData(buffer, rect.size.width, rect.size.height, bytewidth);

	return createMMBitmap(buffer, rect.size.width, rect.size.height, bytewidth,
	                      bitsPerPixel, bytesPerPixel);
#elif defined(USE_X11)
	MMBitmapRef bitmap;

	Display *display = XOpenDisplay(NULL);
	XImage *image = XGetImage(display,
	                          XDefaultRootWindow(display),
	                          (int)rect.origin.x,
	                          (int)rect.origin.y,
	                          (unsigned int)rect.size.width,
	                          (unsigned int)rect.size.height,
	                          AllPlanes, ZPixmap);
	XCloseDisplay(display);
	if (image == NULL) return NULL;

	bitmap = createMMBitmap((uint8_t *)image->data,
	                        rect.size.width,
	                        rect.size.height,
	                        (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
	                     * copy it. */
	XDestroyImage(image);

	return bitmap;
#elif defined(IS_WINDOWS)
	MMBitmapRef bitmap;
	void *data;
	HDC screen = NULL, screenMem = NULL;
	HBITMAP dib;
	BITMAPINFO bi;

	/* Initialize bitmap info. */
	bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
   	bi.bmiHeader.biWidth = (long)rect.size.width;
   	bi.bmiHeader.biHeight = -(long)rect.size.height; /* Non-cartesian, please */
   	bi.bmiHeader.biPlanes = 1;
   	bi.bmiHeader.biBitCount = 32;
   	bi.bmiHeader.biCompression = BI_RGB;
   	bi.bmiHeader.biSizeImage = (DWORD)(4 * rect.size.width * rect.size.height);
	bi.bmiHeader.biXPelsPerMeter = 0;
	bi.bmiHeader.biYPelsPerMeter = 0;
	bi.bmiHeader.biClrUsed = 0;
	bi.bmiHeader.biClrImportant = 0;

	screen = GetDC(NULL); /* Get entire screen */
	if (screen == NULL) return NULL;

	/* Get screen data in display device context. */
   	dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0);

	/* Copy the data into a bitmap struct. */
	if ((screenMem = CreateCompatibleDC(screen)) == NULL ||
	    SelectObject(screenMem, dib) == NULL ||
	    !BitBlt(screenMem, 
	            (int)rect.origin.x, 
	            (int)rect.origin.y, 
	            (int)rect.size.width,
	            (int)rect.size.height, screen, 0, 0, SRCCOPY)) {
		/* Error copying data. */
		ReleaseDC(NULL, screen);
		DeleteObject(dib);
		if (screenMem != NULL) DeleteDC(screenMem);

		return NULL;
	}

	bitmap = createMMBitmap(NULL,
	                        rect.size.width,
	                        rect.size.height,
	                        4 * rect.size.width,
	                        (uint8_t)bi.bmiHeader.biBitCount, 
	                        4);

	/* Copy the data to our pixel buffer. */
	if (bitmap != NULL) {
		bitmap->imageBuffer = malloc(bitmap->bytewidth * bitmap->height);
		memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height);
	}

	ReleaseDC(NULL, screen);
	DeleteObject(dib);
	DeleteDC(screenMem);

	return bitmap;
#endif
}
Пример #2
0
MMBitmapRef newMMBitmapFromBMP(const char *path, MMBMPReadError *err)
{
	FILE *fp;
	struct BITMAP_FILE_HEADER fileHeader = {0}; /* Initialize elements to 0. */
	struct BITMAP_INFO_HEADER dibHeader = {0};
	uint32_t headerSize = 0;
	uint8_t bytesPerPixel;
	size_t bytewidth;
	uint8_t *imageBuf;

	if ((fp = fopen(path, "rb")) == NULL) {
		if (err != NULL) *err = kBMPAccessError;
		return NULL;
	}

	/* Initialize error code to generic value. */
	if (err != NULL) *err = kBMPGenericError;

	if (fread(&fileHeader, sizeof(fileHeader), 1, fp) == 0) goto bail;

	/* Convert from little-endian if it's not already. */
	convertBitmapFileHeader(&fileHeader);

	/* First two bytes should always be 0x4D42. */
	if (fileHeader.magic != BMP_MAGIC) {
		if (err != NULL) *err = kBMPInvalidKeyError;
		goto bail;
	}

	/* Get header size. */
	if (fread(&headerSize, sizeof(headerSize), 1, fp) == 0) goto bail;
	headerSize = swapLittleAndHost32(headerSize);

	/* Back up before reading header. */
	if (fseek(fp, -(long)sizeof(headerSize), SEEK_CUR) < 0) goto bail;

	if (headerSize == 12) { /* OS/2 v1 header */
		struct BITMAP_CORE_HEADER coreHeader = {0};
		if (fread(&coreHeader, sizeof(coreHeader), 1, fp) == 0) goto bail;

		dibHeader.width = coreHeader.width;
		dibHeader.height = coreHeader.height;
		dibHeader.colorPlanes = coreHeader.colorPlanes;
		dibHeader.bitsPerPixel = coreHeader.bitsPerPixel;
	} else if (headerSize == 40 || headerSize == 108 || headerSize == 124) {
		/* Windows v3/v4/v5 header */
		/* Read only the common part (v3) and skip over the rest. */
		if (fread(&dibHeader, sizeof(dibHeader), 1, fp) == 0) goto bail;
	} else {
		if (err != NULL) *err = kBMPUnsupportedHeaderError;
		goto bail;
	}

	convertBitmapInfoHeader(&dibHeader);

	if (dibHeader.colorPlanes != 1) {
		if (err != NULL) *err = kBMPInvalidColorPanesError;
		goto bail;
	}

	/* Currently only 24-bit and 32-bit are supported. */
	if (dibHeader.bitsPerPixel != 24 && dibHeader.bitsPerPixel != 32) {
		if (err != NULL) *err = kBMPUnsupportedColorDepthError;
		goto bail;
	}

	if (dibHeader.compression != kBMP_RGB) {
		if (err != NULL) *err = kBMPUnsupportedCompressionError;
		goto bail;
	}

	/* This can happen because we don't fully parse Windows v4/v5 headers. */
	if (ftell(fp) != (long)fileHeader.imageOffset) {
		fseek(fp, fileHeader.imageOffset, SEEK_SET);
	}

	/* Get bytes per row, including padding. */
	bytesPerPixel = dibHeader.bitsPerPixel / 8;
	bytewidth = ADD_PADDING(dibHeader.width * bytesPerPixel);

	imageBuf = readImageData(fp, dibHeader.width, abs(dibHeader.height),
	                         bytesPerPixel, bytewidth);
	fclose(fp);

	if (imageBuf == NULL) {
		if (err != NULL) *err = kBMPInvalidPixelDataError;
		return NULL;
	}

	/* A negative height indicates that the image is flipped.
	 *
	 * We store our bitmaps as "flipped" according to the BMP format; i.e., (0, 0)
	 * is the top left, not bottom left. So we only need to flip the bitmap if
	 * the height is NOT negative. */
	if (dibHeader.height < 0) {
		dibHeader.height = -dibHeader.height;
	} else {
		flipBitmapData(imageBuf, dibHeader.width, dibHeader.height, bytewidth);
	}

	return createMMBitmap(imageBuf, dibHeader.width, dibHeader.height,
	                      bytewidth, (uint8_t)dibHeader.bitsPerPixel,
	                      bytesPerPixel);

bail:
	fclose(fp);
	return NULL;
}