Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Stretching an Image

This thread is locked; no one can reply to it. rss feed Print
Stretching an Image
someone972
Member #7,719
August 2006
avatar

How do I keep the aspect ratio of an image when using stretch_blit????

______________________________________
As long as it remains classified how long it took me to make I'll be deemed a computer game genius. - William Labbett
Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why. -Unknown
I have recklessly set in motion a chain of events with the potential to so-drastically change the path of my life that I can only find it to be beautifully frightening.

Matthew Leverton
Supreme Loser
January 1999
avatar

By multiplying the height and width by the same value.

FMC
Member #4,431
March 2004
avatar

You just need to multiply both height and width by the same number, to keep the proportion.
Es.

stretch_blit(source, dest, 0, 0, source->w, source->h, dest_x, dest_y, source->w*2, source->h*2);
//stretch_blit(BITMAP *source, BITMAP *dest, int source_x, source_y, source_width, source_height, int dest_x, dest_y, dest_width, dest_height);

[FMC Studios] - [Caries Field] - [Ctris] - [Pman] - [Chess for allegroites]
Written laws are like spiders' webs, and will, like them, only entangle and hold the poor and weak, while the rich and powerful will easily break through them. -Anacharsis
Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. -Mark Twain

someone972
Member #7,719
August 2006
avatar

Still a little unclear on this...
I want the picture to fill either the width or height of the screen. How do I find what number to multiply them by. I am also using many different sizes of images.

______________________________________
As long as it remains classified how long it took me to make I'll be deemed a computer game genius. - William Labbett
Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why. -Unknown
I have recklessly set in motion a chain of events with the potential to so-drastically change the path of my life that I can only find it to be beautifully frightening.

FMC
Member #4,431
March 2004
avatar

What? The code i posted IS an example...

[FMC Studios] - [Caries Field] - [Ctris] - [Pman] - [Chess for allegroites]
Written laws are like spiders' webs, and will, like them, only entangle and hold the poor and weak, while the rich and powerful will easily break through them. -Anacharsis
Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. -Mark Twain

Neil Walker
Member #210
April 2000
avatar

erm, pretend you wish to scale it by a factor of 5, for the dest_width and dest_height, multiply the original bitmap width and height by 5 ;)

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Albin Engström
Member #8,110
December 2006
avatar

FMC just did.. by multiplying with the same value you keep the aspect ratio.. what's so hard too understand? ???

someone972
Member #7,719
August 2006
avatar

Sorry i posted while you posted, see edit above.

So I would do float aspect_ratio = bitmap->w/bitmap->h
or something?

______________________________________
As long as it remains classified how long it took me to make I'll be deemed a computer game genius. - William Labbett
Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why. -Unknown
I have recklessly set in motion a chain of events with the potential to so-drastically change the path of my life that I can only find it to be beautifully frightening.

Albin Engström
Member #8,110
December 2006
avatar

SCREEN_W / image->w..(is the multiply value) this will fill the image on the horizontal axis..

someone972
Member #7,719
August 2006
avatar

Sorry about all the repeat questions, I keep writing a post while others are being put on.

Thanks for the help!8-)

______________________________________
As long as it remains classified how long it took me to make I'll be deemed a computer game genius. - William Labbett
Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why. -Unknown
I have recklessly set in motion a chain of events with the potential to so-drastically change the path of my life that I can only find it to be beautifully frightening.

FMC
Member #4,431
March 2004
avatar

Do something like:

int sW,sH;
sW = SCREEN_W / source->w;
sH = SCREEN_H / source->h;

if(sW < sH) // you must multiply for the SMALLEST size
    stretch_blit(source, dest, 0, 0, source->w, source->h, dest_x, dest_y, source->w*sW, source->h*sW);
else
    stretch_blit(source, dest, 0, 0, source->w, source->h, dest_x, dest_y, source->w*sH, source->h*sH);

[FMC Studios] - [Caries Field] - [Ctris] - [Pman] - [Chess for allegroites]
Written laws are like spiders' webs, and will, like them, only entangle and hold the poor and weak, while the rich and powerful will easily break through them. -Anacharsis
Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. -Mark Twain

BAF
Member #2,981
December 2002
avatar

Em, that code won't work, FMC. This is probably closer to what he wants (you don't want to just multiply by the screen width/height, you would get a HUGE image).

float factor = (SCREEN_W > SCREEN_H ? SCREEN_W : SCREEN_H) / float(SCREEN_W > SCREEN_H ? source->w : source->h);

stretch_blit(source, dest, 0, 0, source->w, source->h, destx, desty, source->w * factor, source->h * factor);

[edit] Did you change your code? I didn't see the division in your sw/sh before. Anyway, your code still won't work, because it will come out as an integer, not a float.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

someone972 said:

I want the picture to fill either the width or height of the screen. How do I find what number to multiply them by. I am also using many different sizes of images.

If the aspect ratio of the screen and the image are not the same , you need to adjust the scale accordingly. Find the ratio of screen to source bitmap for both x and y. Now use the smaller of the two for the actual stretching ratio.

Okay so take for example a tall picture like 100 X 200 using a screen of 640 X 480.
Ratio of screen_x to source_x = 640/100 = 32/5 = 6.4
Ratio of screen_y to source_y = 480/200 = 12/5 = 2.4

Since the smaller ratio is screen_y to source_y and stretch_blit doesn't accept a ratio as its parameter , you need to scale the x yourself.
Actual stretch ratio = 2.4 , so the destination width will be
dest_width = static_cast<int>( 2.4*( static_cast<double>(bmp->w) ) );

and since the height of the screen is completely filled , the destination height
is just the height of the screen.
dest_height = SCREEN_H;

Note : static_cast<int> only truncates the decimal portion , you may want to round instead.

If you want to center it then subtract the destination_width from the screen_width and divide by 2 to find the left or top position.
dest_x = (SCREEN_W - dest_width) / 2;

Since it's height already takes up the whole screen , destination_y will just be 0.
dest_y = (SCREEN_H - dest_height) / 2; // SCREEN_H and dest_height are equal

So for this case use :
stretch_blit(bmp , screen , 0 , 0 , bmp->w , bmp->h , dest_x , dest_y , dest_width , dest_height);

This will be scaled up to the maximum size that will fit in the screen and will retain its original aspect ratio.

Now you just need to take into account the other cases (where screen_to_source ratio's of x and y are equal and where the x ratio is smaller).

BAF
Member #2,981
December 2002
avatar

I just posted the code that does that.

someone972
Member #7,719
August 2006
avatar

Thanks everyone for your help! I'm still having a few issues, but I'll work them out.;D

______________________________________
As long as it remains classified how long it took me to make I'll be deemed a computer game genius. - William Labbett
Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why. -Unknown
I have recklessly set in motion a chain of events with the potential to so-drastically change the path of my life that I can only find it to be beautifully frightening.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

BAF said:

I just posted the code that does that.

BAF's code restated :

float factor;
if (SCREEN_W > SCREEN_H) {
  factor = SCREEN_W / float(source->w);
} else {
  factor = SCREEN_H / float(source->h);
}

This is not the same as :

1double ratio_screen_x_to_source_x = static_cast<double>(SCREEN_W) / static_cast<double>(source->w);
2double ratio_screen_y_to_source_y = static_cast<double>(SCREEN_H) / static_cast<double>(source->h);
3 
4double ratio_to_use;
5int dest_width;
6int dest_height;
7if (ratio_screen_x_to_source_x == ratio_screen_y_to_source_y) {
8 ratio_to_use = ratio_screen_x_to_source_x;// can use either since they are the same
9 dest_width = SCREEN_W;
10 dest_height = SCREEN_H;
11} else {
12 if (ratio_screen_x_to_source_x < ratio_screen_y_to_source_y) {
13 ratio_to_use = ratio_screen_x_to_source_x;
14 // since "ratio_screen_x_to_source_x * (source->w) = SCREEN_W" then just assign
15 dest_width = SCREEN_W;
16 dest_height = static_cast<int>(ratio_to_use*static_cast<double>(source->h));
17 } else {
18 ratio_to_use = ratio_screen_y_to_source_y;
19 dest_width = static_cast<int>(ratio_to_use*static_cast<double>(source->w));
20 // since "ratio_screen_y_to_source_y * (source->h) = SCREEN_H" then just assign
21 dest_height = SCREEN_H;
22 }
23}
24// To display it centered
25stretch_blit(source , screen , 0 , 0 , source->w , source->h ,
26 (SCREEN_W - source->w) / 2 , (SCREEN_H - source->h) / 2 ,
27 dest_width , dest_height);

BAF -
Your code doesn't decide which factor to use based on which y_to_y or x_to_x factor is smaller. It decides based on whether SCREEN_W is larger than SCREEN_H. So when SCREEN_W is larger than SCREEN_H then it will fail if (SCREEN_W / source->w) is greater than (SCREEN_H / source->h) since using the larger scale of the two results in excess magnification.

Quick example using your code
A screen of 200 X 100 and a bitmap of 10 X 50.
SCREEN_W is larger than SCREEN_H so :
factor = SCREEN_W / bitmap_width = 200 / 10
factor = 20
Magnifying the bitmap by 20 gives
20*10 = 200
20*50 = 1000
So it would fit x-wise , but would be way too tall.

It's nice when things can be coded nice and simply , but it just didn't work this time.:-/

FMC
Member #4,431
March 2004
avatar

Quote:

[edit] Did you change your code? I didn't see the division in your sw/sh before. Anyway, your code still won't work, because it will come out as an integer, not a float.

I blame the int thingy for it being 1am when i posted ;)

Quote:

It's nice when things can be coded nice and simply , but it just didn't work this time

What's wrong with my code?

float sW,sH;
sW = SCREEN_W / source->w;
sH = SCREEN_H / source->h;

if(sW < sH) // you must multiply for the SMALLEST size
    stretch_blit(source, dest, 0, 0, source->w, source->h, dest_x, dest_y, source->w*sW, source->h*sW);
else
    stretch_blit(source, dest, 0, 0, source->w, source->h, dest_x, dest_y, source->w*sH, source->h*sH);

[FMC Studios] - [Caries Field] - [Ctris] - [Pman] - [Chess for allegroites]
Written laws are like spiders' webs, and will, like them, only entangle and hold the poor and weak, while the rich and powerful will easily break through them. -Anacharsis
Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. -Mark Twain

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

FMC -

int a = 3;
int b = 4;
cout << (a / b) << endl;// will print 0 - integer division truncates any decimal portion
int x = 5;
float y = 4.5;
cout << (x*y) << endl;// will it print 20 or 22.5?

Does y get converted to int type or does x get converted to float type to perform the multiplication?

If the result ends up as float type , you passed a bad parameter unless the compiler supplies a conversion for you , which it shouldn't do in a function call.

If it ends up as int type then the compiler (un)helpfully converted y from 4.5 to 4 for you which gives you 20 instead of 22.5 for the scaled up size.

You need to cast the source->w and source->h to a float first , multiply by the appropriate scale and then cast it back to an integer.

This may still give you an off by one error due to truncation in the cast back to an integer. This wouldn't be very noticeable in the smaller dimension of the magnified picture but it might be noticeable in the larger dimension (the one that gets magnified to SCREEN_W or SCREEN_H). Imagine the screen was a sub-bitmap of the screen and had been outlined nicely but then there was a black line just above the bottom border. No fun.
Floats often come out as slightly less than the real value they would represent anyway. (.999999995 != 1) but it would still be truncated to 0.

Your way is actually a lot simpler than mine , I must not have read your post closely enough. Sorry.:-/

aj5555
Member #9,033
September 2007

why does stretch_blit() crash when you pass is out-of-bounds values, shouldn't it just clip ?

ImLeftFooted
Member #3,935
October 2003
avatar

I wish you were coding a webpage, so i could just say:

convert 900x800 input.png output.png

But alas, it sounds like you aren't, so heres some code that should do what convert would have done in that scenario, plus some added centering.

1void special_blit(BITMAP *src, BITMAP *dest = screen)
2{
3 // Given: src->w * wval = dest->w
4 float wval = dest->w / float(src->w);
5 float hval = dest->h / float(src->h);
6
7 // Pick which direction is master, horizontal or vertical.
8 if(src->w * SCREEN_H > src->h * SCREEN_W)
9 hval = wval;
10 else
11 wval = hval;
12 
13 const int wnew = int(src->w * wval);
14 const int hnew = int(src->h * hval);
15 
16 // dest coordinates are found by taking 'free' extra space and halving it.
17 stretch_blit(src, dest, 0, 0, src->w, src->h,
18 (dest->w - wnew) / 2, (dest->h - hnew) / 2, wnew, hnew);
19}

The code hasn't been compiled or tested so YMMV, but you hopefully get the idea.

Go to: