I'm working in a project where Cairo was chosen as the graphics library (running on Xlib) in an OpenSUSE Linux environment. I have very little experience working with graphics libraries or graphic file formats, and I was wondering if it is possible to draw a Windows bitmap image to a Cairo surface? It appears to be relatively straightforward to draw a png in Cairo, but I've been looking around everywhere for information on drawing bitmaps and couldn't really find anything. I pieced together the following code:
int height = 256;
int width = 256;
cairo_format_t format = CAIRO_FORMAT_RGB24;
int stride = cairo_format_stride_for_width (format, width);
unsigned char *bitmapData;
bitmapData = (unsigned char *)(malloc (stride * height));
std::ifstream myFile ("exampleBitmapImage.bmp", std::ios::in | std::ios::binary);
myFile.read ((char *)bitmapData, stride * height);
cairo_surface_t *imageSurface = cairo_image_surface_create_for_data (bitmapData, format, width, height, stride);
cairo_set_source_surface (cs, imageSurface, 0, 0);
cairo_paint (cs);
cairo_show_page (cs);
cairo_surface_destroy (imageSurface);
myFile.close();
Strangely, when I run this it displays the image upside-down and backwards at 1/64 of its size 8 times in a row, and then fills out what would be the remainder of the image size (the remaining 7/8 of the image) with black. I suspect it has something to do with the file format, and that I'm parsing and feeding the binary data incorrectly and with improper settings to Cairo. Can anyone give guidance on how to get this working properly? I apologize for my lack of knowledge and wish to understand this problem better, and any help is greatly appreciated, thanks! :)
Multiply the stride with -1 that should flip your bitmap.
Look up the BMP file format http://en.wikipedia.org/wiki/BMP_file_format and
implement bitmap header parser and set the encoding correctly.
Right now are guessing the encoding as RGB24 and you have Cairo interpretting the bitmap header as image data.
Related
I draw a screen with OpenGL commands. And I must save this screen to .bmp or .png format. But I can't do it. I am using glReadpixels but I can't do continue. How can I save this drawing in c++ with OpenGL?
Here it comes! you must include WinGDI.h (which i think the GL will do it!)
void SaveAsBMP(const char *fileName)
{
FILE *file;
unsigned long imageSize;
GLbyte *data=NULL;
GLint viewPort[4];
GLenum lastBuffer;
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
bmfh.bfType='MB';
bmfh.bfReserved1=0;
bmfh.bfReserved2=0;
bmfh.bfOffBits=54;
glGetIntegerv(GL_VIEWPORT,viewPort);
imageSize=((viewPort[2]+((4-(viewPort[2]%4))%4))*viewPort[3]*3)+2;
bmfh.bfSize=imageSize+sizeof(bmfh)+sizeof(bmih);
data=(GLbyte*)malloc(imageSize);
glPixelStorei(GL_PACK_ALIGNMENT,4);
glPixelStorei(GL_PACK_ROW_LENGTH,0);
glPixelStorei(GL_PACK_SKIP_ROWS,0);
glPixelStorei(GL_PACK_SKIP_PIXELS,0);
glPixelStorei(GL_PACK_SWAP_BYTES,1);
glGetIntegerv(GL_READ_BUFFER,(GLint*)&lastBuffer);
glReadBuffer(GL_FRONT);
glReadPixels(0,0,viewPort[2],viewPort[3],GL_BGR,GL_UNSIGNED_BYTE,data);
data[imageSize-1]=0;
data[imageSize-2]=0;
glReadBuffer(lastBuffer);
file=fopen(fileName,"wb");
bmih.biSize=40;
bmih.biWidth=viewPort[2];
bmih.biHeight=viewPort[3];
bmih.biPlanes=1;
bmih.biBitCount=24;
bmih.biCompression=0;
bmih.biSizeImage=imageSize;
bmih.biXPelsPerMeter=45089;
bmih.biYPelsPerMeter=45089;
bmih.biClrUsed=0;
bmih.biClrImportant=0;
fwrite(&bmfh,sizeof(bmfh),1,file);
fwrite(&bmih,sizeof(bmih),1,file);
fwrite(data,imageSize,1,file);
free(data);
fclose(file);
}
Unless you're feeling particularly ambitious (or perhaps masochistic) you probably want to use a library like DevIL that already supports this. The current version can load and/or save in both PNG and BMP formats, along with a few dozen others.
Compared to something like IJG, this is oriented much more heavily toward working with OpenGL or DirectX (e.g., it can load a file fairly directly into an texture or vice versa).
I know you're asking for raster formats, but an indirect way would be to first output vector graphics through gl2ps (http://www.geuz.org/gl2ps/). Examples of usage are provided with the package and on the site (http://www.geuz.org/gl2ps/#tth_sEc3).
Then, the vector output can be converted to the format of your choice using another tool (Inkscape, Image/GraphicsMagick, etc.) or library. An added benefit is you can convert to bitmaps of any resolution in the future.
One thing need to be fixed at:
bmih.biXPelsPerMeter = bmih.biYPelsPerMeter = 0;
Otherwise, some picture edit can not open correctly.
I have a superSpeed usb 3.0 Ximea camera and I'm trying to code an application with a Ximea camera that consists on computer vision and machine learning.
I've been able to alocate the frames captured by the camera in it's buffer but I can find the way to save those images or frames as an JPEG or BMP file. I don't know if it's just a command line in my script or I need some kind of libraries to do it.
The images are aquired using these commands:
#define EXPECTED_IMAGES 10
for (int images=0;images < EXPECTED_IMAGES;images++)
{
// getting image from camera
stat = xiGetImage(xiH, 5000, &image);
HandleResult(stat,"xiGetImage");
printf("Image %d (%dx%d) received from camera\n", images, (int)image.width, (int)image.height);
}
As I can extract the data from the images, I suppose that the frame is still in the buffer, but I can't figure out the way to save it as a JPEG or BMP file in the computer.
I would appreciate any help with the code.
Thank you!
Aha, saving the image. I think you might have gotten the answer by now.
But here is mine, and I hope this will be useful for anyone working with machine vision cameras.
I have been working with XIMEA for quite a while now. XIMEA API does not include any functions to save images from the buffer to hard drive. So, you need to write your own function or use some library to save out images. And I think, essentially it all comes down to whether it's RAW or compressed image and what kind of image format you want to save out. ie. BMP, JPEG, PNG, PGM, EXR ......
Let's make couple assumptions first.
Here I assume you want to save out 8bit per pixel RAW image having a resolution of 1024*1024. The size of the image will be 8bit * 1024 * 1024 = 8388608bit = 1048576btye ~= 1MB
By looking at your code, you are using XIMEA API in C++.
Okay...... Here are two ways I used most often to save out images from XIMEA.
Writing all the image pixels to a binary file with a proper header according to the format you want to save out. Here is an example saving a data to a PGM format image.
FILE *file;
char fileName = "example.pgm";
char *image;
int width = 1024;
int height = 1024;
int byte_per_pixel = 1;
int max_pixel_value = 255;
file = fopen (fileName , "w+bx");
if(file == NULL){
fprintf(stderr, "Cannot open %s\n", fileName);
return -1;
}
size_t n = 0;
n += fprintf(file, "P5\n# Comment goes here!\n%d %d\n%d\n", width, height, max_pixel_value);
n += fwrite(image, 1, width * height * byte_per_pixel, file);
fclose (fileToSave);
Saving image to PGM may seem easy but when you need to save an image having pixel depth higher than 8bit, you need to deal with endianness issue, since PGM big-endian format. Here is a link to Netpbm formats if you want to read more about it. https://en.wikipedia.org/wiki/Netpbm_format
And also, other formats may have way more complicated data structure then you cannot just simply put down a header. So, using an image library or OpenCV will be a lot less cumbersome.
The handy OpenCV imwrite. Since you are gonna deal with pixels, OpenCV is a good library to have. OpenCV is a powerful library helps you with manipulating matrixes easier than ever. And it comes with a lot of useful stuff like GPU accelerated OpenCV functions. Back to the topic, imwrite can save images to many formats. Here is an example I wrote to save RAW data to PNG format.
string fileName = "example.png";
char *image;
int width = 1024;
int height = 1024;
int byte_per_pixel = 1;
int max_pixel_value = 255;
cv::Mat img_raw = cv::Mat(height, width, CV_8UC1, image);
vector compression_params;
compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
compression_params.push_back(0);
cv::imwrite(PNGFileName, img_raw, compression_params);
imwirte will determine what kind of format you want to save out based on the filename extension. And just a couple lines of code. OpenCV saves out the image for you effortlessly. Here is a link to OpenCV documentation of imwirte, http://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html?highlight=imwrite
I hope my answer can help you and others are wondering how to save out images.
to store images from XIMEA cameras I would recommend to use the OpenCV library
as it provides tools for storing both JPEG and BMP image formats. Please download
a short example that demonstrates the storing of several different data formats
from the camera to JPEG and BMP images. Download the archive with MSVC 2013 project and OpenCV3.0 binaries from here and use password SHWJGRAIHFLG for
extraction.
If you should have any other questions concerning XIMEA products, please visit
and register directly on the XIMEA customer support. Thank you.
Best regards,
XIMEA team
I am trying to set a background image for one of my windows created with Xlib.
I would like the image to be a JPEG or PNG. I downloaded DevIL (which I prefer to use because it supports a lot of formats).
So, my questions, is, how do I do it? I can't find any specific tutorial or help.
I understand how I can use DevIL to load an image into a stream, but how do I put that on the window? I found an answer here: Load image onto a window using xlib but I don't know how and which function should receive the image bytes.
As I also understand, I should have a XImage that would hold all the image, and which I would use with XPutImage. What I don't understand is how do I send the image's bytes from DevIL to XImage.
Does somebody know any helpful page or maybe some clues about how I should do it?
Thanks!
The Xlib function used to create an XImage is XCreateImage, and its usage looks like this (you can read a full description in the link):
XImage *XCreateImage(display, visual, depth, format, offset, data,
width, height, bitmap_pad, bytes_per_line)
where the relevant argument for your specific question would be data, a char* that points to where you keep the image data loaded in with DevIL. With this, you should then be able to follow the steps in the other answer you already found.
Edited to add:
You still have to tell DevIL how to format your image data so that XCreateImage can understand it. For example the following pair of function calls will create an XImage that appears correctly:
ilCopyPixels(
0, 0, 0,
image_width, image_height, 1,
IL_BGRA, IL_UNSIGNED_BYTE,
image_data
);
// ...
XImage* background = XCreateImage(
display,
XDefaultVisual(display, XDefaultScreen(display)),
XDefaultDepth(display, XDefaultScreen(display)),
ZPixmap,
0,
image_data,
image_width,
image_height,
32,
0
);
, if you instead chose IL_RGBA, the colors will be off!
I have an OpenGL game, and I want to save what's shown on the screen to a video.
How can I do that? Is there any library or how-to-do-it?
I don't care about compression, I need the most efficient way so hopefully the FPS won't drop.
EDIT:
It's OpenGL 1.1 and it's working on Mac OSX though I need it to be portable.
There most certainly are great video capture software out there you could use to capture your screen, even when running a full screen OpenGL game.
If you are using new versions of OpenGL, as genpfault has mentioned you can use PBOs. If you are using legacy OpenGL (version 1.x), here's how you can capture the screen:
glFinish(); // Make sure everything is drawn
glReadBuffer(GL_FRONT);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glReadPixels(blx, bly, w, h, mode, GL_UNSIGNED_BYTE, GL_BGRA);
where blx and bly are the bottom left coordinates of the part of the screen you want to capture (in your case (0, 0)) and w and h are the width and height of the box to be captured. See the reference for glReadPixels for more info, such as the last parameter.
Writing captured screen (at your desired rate, for example 24 fps) to a video file is a simple matter of choosing the file format you want (for example raw video), write the header of the video and write the images (image by image if raw, or image differences in some other format etc)
Use Pixel Buffer Objects (PBOs).
I'm trying to generate ImageMagick images from SDL pixel data. Here's what the GIF looks like so far. (This GIF is slower than the one below on purpose.)
http://www.starlon.net/images/combo.gif
Here's what it's supposed to look like. Notice in the above image that the pixels seem to be overlayed on top of other pixels.
http://www.starlon.net/images/combo2.gif
Here's where the GIF is actually created.
void DrvSDL::WriteGif() {
std::list<Magick::Image> gif;
for(std::list<Magick::Blob>::iterator it = image_.begin(); it != image_.end(); it++) {
Magick::Geometry geo(cols_ * pixels.x, rows_ * pixels.y);
Magick::Image image(*it, geo, 32, "RGB");
gif.push_back(image);
LCDError("image");
}
for_each(gif.begin(), gif.end(), Magick::animationDelayImage(ani_speed_));
Magick::writeImages(gif.begin(), gif.end(), gif_file_);
}
And here's where the Blob is packed.
image_.push_back(Magick::Blob(surface_->pixels, rows_ * pixels.y * surface_->pitch));
And here's how I initialize the SDL surface.
surface_ = SDL_SetVideoMode(cols_ * pixels.x, rows_ * pixels.y, 32, SDL_SWSURFACE);
The top image is normally caused by a misaligned buffer. The SDL buffer is probably not DWORD aligned and the ImageMagick routines expect the buffer to be aligned on a DWORD. This is very common in bitmap processing. The popular image processing library - Leadtools, commonly, requires DWORD aligned data. This is mostly case with monochrome and 32 bit color but can be the case for any color depth.
What you need to do is write out a DWORD aligned bitmap from your SDL buffer or at least create a buffer that is DWORD aligned.
The ImageMagick API documentation may be able to help clarify this further.
Another thing you might want to try is to clear the buffers to make sure there isn't any data already there. I don't really know IM's API, but pixels overlayed on top of other pixels usually indicates a dirty buffer.