Example #1
0
MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect)
{
	assert(source != NULL);

	if (source->imageBuffer == NULL || !MMBitmapRectInBounds(source, rect)) {
		return NULL;
	} else {
		uint8_t *copiedBuf = NULL;
		const size_t bufsize = rect.size.height * source->bytewidth;
		const size_t offset = (source->bytewidth * rect.origin.y) +
		                      (rect.origin.x * source->bytesPerPixel);

		/* Don't go over the bounds, programmer! */
		assert((bufsize + offset) <= (source->bytewidth * source->height));

		copiedBuf = malloc(bufsize);
		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);
	}
}
Example #2
0
MMBitmapRef copyMMBitmap(MMBitmapRef bitmap)
{
	uint8_t *copiedBuf = NULL;

	assert(bitmap != NULL);
	if (bitmap->imageBuffer != NULL) {
		const size_t bufsize = bitmap->height * bitmap->bytewidth;
		copiedBuf = malloc(bufsize);
		if (copiedBuf == NULL) return NULL;

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

	return createMMBitmap(copiedBuf,
	                      bitmap->width,
	                      bitmap->height,
	                      bitmap->bytewidth,
	                      bitmap->bitsPerPixel,
	                      bitmap->bytesPerPixel);
}
Example #3
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
}
Example #4
0
MMBitmapRef newMMBitmapFromPNG(const char *path, MMPNGReadError *err)
{
	FILE *fp;
	uint8_t header[8];
	png_struct *png_ptr = NULL;
	png_info *info_ptr = NULL;
	png_byte bit_depth, color_type;
	uint8_t *row, *bitmapData;
	uint8_t bytesPerPixel;
	png_uint_32 width, height, y;
	uint32_t bytewidth;

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

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

	/* Validate the PNG. */
	if (fread(header, 1, sizeof header, fp) == 0) {
		if (err != NULL) *err = kPNGReadError;
		goto bail;
	} else if (!png_check_sig(header, sizeof(header))) {
		if (err != NULL) *err = kPNGInvalidHeaderError;
		goto bail;
	}

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) goto bail;

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) goto bail;

	/* Set up error handling. */
	if (setjmp(png_jmpbuf(png_ptr))) {
		goto bail;
	}

	png_init_io(png_ptr, fp);

	/* Skip past the header. */
	png_set_sig_bytes(png_ptr, sizeof header);

	png_read_info(png_ptr, info_ptr);

	/* Convert different image types to common type to be read. */
	bit_depth = png_get_bit_depth(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);

	/* Convert color palettes to RGB. */
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		png_set_palette_to_rgb(png_ptr);
	}

	/* Convert PNG to bit depth of 8. */
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
#ifdef PNG_LIBPNG_VER_SONUM
#if PNG_LIBPNG_VER_SONUM  >= 14
		png_set_expand_gray_1_2_4_to_8(png_ptr);
#else
		png_set_gray_1_2_4_to_8(png_ptr);
#endif
#else
		png_set_gray_1_2_4_to_8(png_ptr);
#endif
	} else if (bit_depth == 16) {
		png_set_strip_16(png_ptr);
	}

	/* Convert transparency chunk to alpha channel. */
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))  {
		png_set_tRNS_to_alpha(png_ptr);
	}

	/* Convert gray images to RGB. */
	if (color_type == PNG_COLOR_TYPE_GRAY ||
	    color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_gray_to_rgb(png_ptr);
	}

	/* Ignore alpha for now. */
	if (color_type & PNG_COLOR_MASK_ALPHA) {
		png_set_strip_alpha(png_ptr);
	}

	/* Get image attributes. */
	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);
	bytesPerPixel = 3; /* All images decompress to this size. */
	bytewidth = ADD_PADDING(width * bytesPerPixel); /* Align width. */

	/* Decompress the PNG row by row. */
	bitmapData = calloc(1, bytewidth * height);
	row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
	if (bitmapData == NULL || row == NULL) goto bail;
	for (y = 0; y < height; ++y) {
		png_uint_32 x;
		const uint32_t rowOffset = y * bytewidth;
		uint8_t *rowptr = row;
		png_read_row(png_ptr, (png_byte *)row, NULL);

		for (x = 0; x < width; ++x) {
			const uint32_t colOffset = x * bytesPerPixel;
			MMRGBColor *color = (MMRGBColor *)(bitmapData + rowOffset + colOffset);
			color->red = *rowptr++;
			color->green = *rowptr++;
			color->blue = *rowptr++;
		}
	}
	free(row);

	/* Finish reading. */
	png_read_end(png_ptr, NULL);
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	fclose(fp);

	return createMMBitmap(bitmapData, width, height,
	                      bytewidth, bytesPerPixel * 8, bytesPerPixel);

bail:
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	fclose(fp);
	return NULL;
}
Example #5
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;
}
Example #6
0
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect)
{
#if defined(IS_MACOSX)

	size_t bytewidth;
	uint8_t bitsPerPixel, bytesPerPixel;
	uint8_t *buffer;

	CGDirectDisplayID displayID = CGMainDisplayID();

	//Replacement for CGDisplayBitsPerPixel. 
	CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayID);
	size_t depth = 0;
	
	CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode);
	if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
		depth = 32;
	else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
		depth = 16;
	else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
		depth = 8;

	bitsPerPixel = (uint8_t) depth; 
	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;

	CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height));

    // Request access to the raw pixel data via the image's DataProvider.
    CGDataProviderRef provider = CGImageGetDataProvider(image);
    CFDataRef data = CGDataProviderCopyData(provider);

    size_t width, height;    
    width = CGImageGetWidth(image);
    height = CGImageGetHeight(image); 
    size_t bpp = CGImageGetBitsPerPixel(image) / 8;

    uint8 *pixels = malloc(width * height * bpp);
    memcpy(pixels, CFDataGetBytePtr(data), width * height * bpp);
    CFRelease(data); 
   	CGImageRelease(image); 

	return createMMBitmap(pixels, 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
}