How to resize Window to loaded Image? - c

Is there a way that to resize the window in SDL to fit the loaded image size? currently when you resize it copies what was behind the window.
This is my Load Image Function:
void userImage(SDL_Surface *surface, SDL_Window *window)
{
SDL_Surface *userLoadImage;
char FileLocation[200];
printf( "Please Enter the file location:\n" );
fgets(FileLocation, 200, stdin );
fflush(stdin);
FileLocation[strcspn(FileLocation,"\n")]=0;
char *const picturePath = FileLocation;
userLoadImage = IMG_Load( picturePath );
int width = userLoadImage->w; //Get the width
int height = userLoadImage ->h; //Get the height
printf("image width = %d\n", width);
printf("image width = %d\n", height);
SDL_BlitSurface(userLoadImage, NULL, surface, NULL);
SDL_SetWindowSize( window, width, height);
}

This is the way I fixed it: All i changed was to reassign the window to the surface 'surface = SDL_GetWindowSurface(window);'
void userImage(SDL_Surface *surface, SDL_Window *window)
{
SDL_Surface *userLoadImage;
char FileLocation[200];
printf( "Please Enter the file location:\n" );
fgets(FileLocation, 200, stdin );
fflush(stdin);
FileLocation[strcspn(FileLocation,"\n")]=0;
char *const picturePath = FileLocation;
userLoadImage = IMG_Load( picturePath );
int width = userLoadImage->w; //Get the width
int height = userLoadImage ->h; //Get the height
SDL_SetWindowSize( window, width, height);
surface = SDL_GetWindowSurface(window);
SDL_BlitSurface(userLoadImage, NULL, surface, NULL);
}

Here is an SDL method for scaling a surface that may do what you are looking for:
SDL_Surface* SDL_ScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height)
{
for(Sint32 y = 0; y < Surface->h; y++) //Run across all Y pixels.
for(Sint32 x = 0; x < Surface->w; x++) //Run across all X pixels.
for(Sint32 o_y = 0; o_y < _stretch_factor_y; ++o_y) //Draw _stretch_factor_y pixels for each Y pixel.
for(Sint32 o_x = 0; o_x < _stretch_factor_x; ++o_x) //Draw _stretch_factor_x pixels for each X pixel.
DrawPixel(_ret, static_cast<Sint32>(_stretch_factor_x * x) + o_x,
static_cast<Sint32>(_stretch_factor_y * y) + o_y, ReadPixel(Surface, x, y));
}
The example, and much more is on this page.

Related

Slow pixel per pixel rendering with SDL2's textures

I am trying to create a image pixel-per-pixel and display it on the screen with SDL. The image has to be refreshed and displayed again ~50 times per second (I am looking for a 50 FPS game). I tried to create a simple program to illustrate what I want to do: I create a 1280 * 720 window and texture which I alternately fill with green and red.
The problem is that the code runs very slowly (~8 FPS). Where did I mess up?
Here's my code
SDL_Texture *display;
SDL_Window *window;
SDL_Renderer *renderer;
int x;
int y;
int a = 255;
int b = 0;
window = SDL_CreateWindow(gl_title, SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, gl_width, gl_height, 0);
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED |
SDL_RENDERER_TARGETTEXTURE |
SDL_RENDERER_PRESENTVSYNC);
display = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET, gl_width, gl_height);
while (true)
{
SDL_SetRenderTarget(renderer, display);
SDL_SetRenderDrawColor(renderer, a, b, 0, 255);
for (x = 0; x < gl_width; ++x)
{
for (y = 0; y < gl_height; ++y)
{
SDL_RenderDrawPoint(renderer, x, y);
}
}
a = a == 255 ? 0 : 255;
b = b == 255 ? 0 : 255;
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, display, NULL, NULL);
SDL_RenderPresent(renderer);
}
Drawing on a screen using a function for every pixel is going to be slow. You can manually write the pixels in a loop and avoid the cost of calling the function every time or use one of the SDL provided functions that do that for you:
SDL_RenderFillRect
SDL_RenderDrawLines
SDL_RenderDrawPoints
SDL_RenderDrawRect

Changes made to image surface aren't reflected when painting

I have a small code snippet which loads an image from a PNG file, then modifies the image data in memory by making a specific color transparent (setting alpha to 0 for that color). Here's the code itself:
static gboolean expose (GtkWidget *widget, GdkEventExpose *event, gpointer userdata)
{
int width, height, stride, x, y;
cairo_t *cr = gdk_cairo_create(widget->window);
cairo_surface_t* image;
char* ptr;
if (supports_alpha)
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */
else
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* opaque white */
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
image = cairo_image_surface_create_from_png ("bg.png");
width = cairo_image_surface_get_width (image);
height = cairo_image_surface_get_height (image);
stride = cairo_image_surface_get_stride (image);
cairo_surface_flush (image);
ptr = (unsigned char*)malloc (stride * height);
memcpy (ptr, cairo_image_surface_get_data (image), stride * height);
cairo_surface_destroy (image);
image = cairo_image_surface_create_for_data (ptr, CAIRO_FORMAT_ARGB32, width, height, stride);
cairo_surface_flush (image);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
char alpha = 0;
unsigned int z = *((unsigned int*)&ptr [y * stride + x * 4]);
if ((z & 0xffffff) == 0xffffff) {
z = (z & ~0xff000000) | (alpha & 0xff000000);
*((unsigned int*) &ptr [y * stride + x * 4]) = z;
}
}
}
cairo_surface_mark_dirty (image);
cairo_surface_write_to_png (image, "image.png");
gtk_widget_set_size_request (GTK_OBJECT (window), width, height);
gtk_window_set_resizable (GTK_OBJECT (window), FALSE);
cairo_set_source_surface (cr, image, 0, 0);
cairo_paint_with_alpha (cr, 0.9);
cairo_destroy (cr);
cairo_surface_destroy (image);
free (ptr);
return FALSE;
}
When I dump the modified data to PNG, transparency is actually there. But when the same data is used as a source surface for painting, there's no transparency. What might be wrong?
Attachments:
image.png - modified data dumped to file for debugging purposes,
demo.png - actual result
bg.png - source image, is omitted due to stackoverflow restrictions, it's simply black rounded rectangle on the white background. Expected result is black translucent rectangle and completely transparent fields, not white, like these on the demo.png.
Setting alpha to 0 means that the color is completely transparent. Since cairo uses pre-multiplied alpha, you have to set the pixel to 0, since otherwise the color components could have higher values than the alpha channels. I think cairo chokes on those super-luminscent pixels.
So instead of this code:
if ((z & 0xffffff) == 0xffffff) {
z = (z & ~0xff000000) | (alpha & 0xff000000);
*((unsigned int*) &ptr [y * stride + x * 4]) = z;
}
You should try the following:
if ((z & 0xffffff) == 0xffffff) {
*((unsigned int*) &ptr [y * stride + x * 4]) = 0;
}
And while we are at it:
Doesn't (z & 0xffffff) == 0xffffff check if the green, blue and alpha channels are all at 100% and ignores the red channel? Are you sure that's really what you want? z == 0xffffffff would be opaque white.
Instead of using unsigned int, it would be better if you used uint32_t for accessing the pixel data. Portability!
Your code assumes that cairo_image_surface_create_from_png() always gives you an image surface with format ARGB32. I don't think that's necessarily always correct and e.g. RGB24 is possible as well.
I think I would do something like this:
for (y = 0; y < height; y++) {
uint32_t row = (uint32_t *) &ptr[y * stride];
for (x = 0; x < width; x++) {
uint32_t px = row[x];
if (is_expected_color(px))
row[x] = 0;
}
}

OpenGL ios 6 screenshot

I am trying to get screenshot of NinevehGL object which is 3D library build on top of OpenGL. So i think OpenGL commands would work here as well.
Problem is screenshot works fine in iOS 5 or earlier but not with iOS6. It works fine in iOS6 simulator as well but not on iOS 6 device. It gives me black background. I have read many posts most of them suggest to put
CAEAGLLayer *eaglLayer = (CAEAGLLayer *) [self theNGLView].layer;
[eaglLayer setDrawableProperties:#{
kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:YES],
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
}];
in init method. which i did but with no luck.
I am using below method to get screenshot.
-(UIImage *)getImage{
GLint width;
GLint height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
NSLog(#"%d %d",width,height);
NSInteger myDataLength = width * height * 4;
// allocate array and read pixels into it.
GLubyte *buffer = (GLubyte *) malloc(myDataLength);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// gl renders "upside down" so swap top to bottom into new array.
// there's gotta be a better way, but this works.
GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width * 4; x++)
{
buffer2[((height - 1) - y) * width * 4 + x] = buffer[y * 4 * width + x];
}
}
// make data provider with data.
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
// prep the ingredients
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
// make the cgimage
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
// then make the uiimage from that
UIImage *myImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpaceRef);
free(buffer);
free(buffer2);
return myImage;
}

How to copy some part of WriteableBitmap?

I have some WriteableBitmap object.
Lets say that the image that is actully on the WriteableBitmap object is 600x400.
I want to copy part of the image - some Rectangle ( for example Rectangle of 100x100 in the middle of the WriteableBitmap ) and paste the copy to some other image control.
How can i do it ?
I suspect you've got this fixed now, but I had the same problem and I found the answer so I thought I'd post it. The code at http://writeablebitmapex.codeplex.com/ has a "Crop" routine that does pretty much what you're after. Once you have a SizeOfArgb constant set to 4, you can use this:
public static WriteableBitmap Crop(this WriteableBitmap bmp, int x, int y, int width, int height)
{
var srcWidth = bmp.PixelWidth;
var srcHeight = bmp.PixelHeight;
// If the rectangle is completly out of the bitmap
if (x > srcWidth || y > srcHeight)
{
return new WriteableBitmap(0, 0);
}
// Clamp to boundaries
if (x < 0) x = 0;
if (x + width > srcWidth) width = srcWidth - x;
if (y < 0) y = 0;
if (y + height > srcHeight) height = srcHeight - y;
// Copy the pixels line by line using fast BlockCopy
var result = new WriteableBitmap(width, height);
for (var line = 0; line < height; line++)
{
var srcOff = ((y + line) * srcWidth + x) * SizeOfArgb;
var dstOff = line * width * SizeOfArgb;
Buffer.BlockCopy(bmp.Pixels, srcOff, result.Pixels, dstOff, width * SizeOfArgb);
}
return result;
}
public static BitmapSource Crop(this BitmapSource bmp, Int32Rect rect)
{
return new CroppedBitmap(bmp, rect);
}

drawing multiple rectangles with Cairo graphics

I'm trying to write a Cairo program to black-fill the entire image and then draw another rectangle inside of it a different color. Eventually, I'm going to make this a program that generates a .png of the current time that looks like a digital clock. For now, this is where I'm getting hung up.
Here's my code:
#include <stdio.h>
#include <cairo.h>
//on color: 0.6, 1.0, 0
//off color: 0.2, 0.4, 0
int prop_number_width;
int prop_number_height;
int prop_width;
int prop_height;
int prop_space_width;
int prop_space_height;
double width;
double height;
double w_unit;
double h_unit;
void draw_number(cairo_t* cr, int unit_width, int num);
int main(int argc, char** argv) {
/* proportional sizes:
* the widths and heights of the diagram
*/
prop_number_width = 5; //how many spaces the number takes up
prop_number_height = 6;
prop_space_width = 1; //extra width on each side
prop_space_height = 1; //extra height on each side
prop_width = 25 + (2 * prop_space_width); //width of diagram
prop_height = 6 + (2 * prop_space_height); //height of diagram
/* actual sizes:
* the pixel value of different sizes
*/
width = 200.0;
height = 100.0;
w_unit = width / prop_width;
h_unit = height / prop_height;
//begin cairo stuff
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)width, (int)height);
cairo_t* cr = cairo_create(surface);
//black fill
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_rectangle(cr, 0.0, 0.0, width, height); //cr ref, x, y, width, height
cairo_fill_preserve(cr);
//draw numbers from left to right
draw_number(cr, 0, 1);
//draw_number(cr, 6, 3);
//draw_number(cr, 14, 3);
//draw_number(cr, 20, 7);
//draw in colons
cairo_destroy(cr);
cairo_surface_write_to_png(surface, "test.png");
cairo_surface_destroy(surface);
return 0;
}
void draw_number(cairo_t* cr, int unit_width, int num) {
//determine the box size that the number will be drawn in
double box_x = w_unit * (prop_space_width + unit_width);
double box_y = h_unit * prop_space_height;
double box_width = w_unit * prop_number_width;
double box_height = h_unit * prop_number_height;
printf("{box_x: %lf box_y: %lf} {box_width: %lf box_height: %lf}\n", box_x, box_y, box_width, box_height);
cairo_set_source_rgb(cr, 0.2, 0.4, 0);
cairo_rectangle(cr, box_x, box_y, box_width, box_height);
cairo_fill_preserve(cr);
}
The problem is with this code it draws the rectangle to take up the whole image where from the printf's it should only take up a small part. Does anybody know how I can make this rectangle show up as the correct size?
I should have looked at the API more carefully. I needed to do cairo_fill() instead of cairo_fill_preserve(). Apparently, the first call to cairo_fill_preserve() was keeping the original rectangle and always filling that one.

Resources