Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Aspect ratios and math -- Aaagh!

Options
  • 03-03-2002 3:12am
    #1
    Banned (with Prison Access) Posts: 16,659 ✭✭✭✭


    I'm writing a thumbnailer and I've got it retaining aspect ratios for square images, but the math involved has overdriven my brain, which has jumped out of my head and flown to the Bahamas for a holiday. I can still hear it screaming in protest.

    I'd like to get it retaining aspects for rectangular images too, so can anyone tell me how to go about it? In the following code, $s is both width and height of the replacement image, and I've plonked that in in both places where required (because I got pissed off with the math).

    [PHP]<?php

    // JPEG load error handler: if we can't load the JPEG, send a pretty image to say so!
    function loadJPEG($f)
    {
    $i = @ImageCreateFromJPEG($f);
    if (!$i) {
    $i = ImageCreate(600, 30);
    $b = ImageColorAllocate($i, 255, 255, 255);
    $t = ImageColorAllocate($i, 0, 0, 0);
    ImageFilledRectangle($i, 0, 0, 150, 30, $b);
    ImageString($i, 2, 5, 5, "Error loading '$f'", $t);
    ImageJPEG($i);
    exit();
    } else {
    return $i;
    }
    }

    // Load the original
    $i1 = loadJPEG("./images/$i");

    // Width & height of the ORIGINAL image
    $w1 = ImageSX($i1);
    $h1 = ImageSY($i1);

    // Width & height of the NEW image (SQUARE!)
    $s = ($s) ? $s : 100;

    // Create the new image
    $i2 = ImageCreate($s, $s);

    // Colouring in
    $c = ImageColorAllocate($i2, 255, 255, 255);
    ImageFill($i2, 0, 0, $c);

    // If the ORIGINAL is square, we can just resize straight
    if ($w1 == $h1) {
    ImageCopyResized($i2, $i1, 0, 0, 0, 0, $s, $s, $w1, $h1);
    }

    // If the width is greater than the height, we'll have some spare vertical space, so we need to center up the copy
    elseif ($w1 > $h1) {
    ImageCopyResized($i2, $i1, 0, (($s - ($s / ($w1 / $h1))) / 2), 0, 0, $s, ($s / ($w1 / $h1)), $w1, $h1);
    }

    // If the height is greater than the width, again, we need to center, but this time we offset from Y
    else {
    ImageCopyResized($i2, $i1, (($s - ($s * ($w1 / $h1))) / 2), 0, 0, 0, ($s * ($w1 / $h1)), $s, $w1, $h1);
    }

    // Send the correct header
    header("Content-Type: image/jpeg");

    // Output the file
    ImageJPEG($i2);

    ?>
    [/PHP]The most important function here, which handles offsets and the like, is ImageCopyResized. Please ask me to explain if (when) I'm not making sense.

    TIA,
    adam


Comments

  • Registered Users Posts: 1,931 ✭✭✭Zab


    Ok, to start with I have to say that I don't know PHP...

    This is what I think you want to do:
    Create a thumbnail that retains aspect ratio with the original
    Create it in a predefined image size
    Blank out the parts of the image that are within that predefined size, but outside of our thumbnail image...

    I've never done this before, and I haven't check it, but this is what I'm thinking:

    srcW and srcH and the source width and height

    destW and destH and the destination width and height ( the whole thumbnail )

    We need to find a single ratio value to use, and thus keep aspect ratio
    ratio = srcH / destH
    
    if srcW / ratio > destW
        // the ratio is too big, the width won't fit
        ratio = srcW / destW
    end if
    

    Now we have our ratio, right?
    So we can compute our destination size:
    thmH = srcH / ratio
    thmW = srcW / ratio
    


    then you do something pretty much along the lines of what you have already done to do the actual copy.

    eg.
    if thmW < destW
        // The presumption in here is that thmH == destH
        ImageCopyResized( dest, src, (destW - thmW) / 2 , srcH, 0, 0, thmW, thmH, srcW, srcH )
    if ....
    

    As I say, I haven't checked it. Its going to need some work anyway ( it would be better to set flags when we are computing the ratio's and check them in the last if statment )...

    Zab


  • Registered Users Posts: 944 ✭✭✭nahdoic


    THe first thing I'd say is that you are confusing yourself making it retain the aspect ratio and still have the image fixed at 100x100. Decide what fixed width or height but not both you would like to base the rest of your calculations on. If you choose a fixed width then your height will vary for each unique width. For the example below all our images are to be reduced to 100 pixels wide, if it is already less than 100 pixels wide then the image is fine as it is.

    I think this is what you are asking because your code does properly re-scale all images (including rectangles) to 100x100, leaving the correct whitespace above and below, or to the left and the right of the rescaled image. What were you asking for?

    This code is working, you can just copy and paste it in adam.

    [PHP]
    <?php

    // JPEG load error handler: if we can't load the JPEG, send a pretty image to say so!
    function loadJPEG($f)
    {
    $i = @ImageCreateFromJPEG($f);
    if (!$i) {
    $i = ImageCreate(600, 30);
    $b = ImageColorAllocate($i, 255, 255, 255);
    $t = ImageColorAllocate($i, 0, 0, 0);
    ImageFilledRectangle($i, 0, 0, 150, 30, $b);
    ImageString($i, 2, 5, 5, "Error loading '$f'", $t);
    ImageJPEG($i);
    exit();
    } else {
    return $i;
    }
    }

    // Load the original
    $i1 = loadJPEG("./images/$i");


    // Width & height of the ORIGINAL image
    $w1 = ImageSX($i1);
    $h1 = ImageSY($i1);

    // the decided width for our thumbnail

    $w2=100;
    $h2=$h1;

    // if the original width is greater than 100 then we want to compress it
    if($w1 > $w2) {
    // Calculate the correct height to use
    $h2= $h1*($w2/$w1);

    // Create the new image
    $i2 = ImageCreate($w2, $h2);

    // Resize the Image appropriately
    ImageCopyResized($i2, $i1, 0, 0, 0, 0, $w2, $h2, $w1, $h1);
    }
    // the image is fine the way it is.
    else {
    $i2 = $i1;
    }

    // Send the correct header
    header("Content-Type: image/jpeg");

    // Output the file
    ImageJPEG($i2);

    ?>
    [/PHP]


  • Registered Users Posts: 944 ✭✭✭nahdoic


    well how did that work out for you?


  • Banned (with Prison Access) Posts: 16,659 ✭✭✭✭dahamsta


    Heh, sorry nahdoic, been farting about with IO/IEDR stuff, haven't had a chance. I'll take a poke at it this evening.

    adam


  • Banned (with Prison Access) Posts: 16,659 ✭✭✭✭dahamsta


    Thanks for your replies folks, and sorry for not replying sooner. You know yourself, you get a bee in your bonnet about something that really isn't all that important. Then you get caught up in other things that may or may not be more important, and forget all about this previously life-threatening problem. Coders, eh?

    THe first thing I'd say is that you are confusing yourself making it retain the aspect ratio and still have the image fixed at 100x100.

    I am not! :)

    Decide what fixed width or height but not both you would like to base the rest of your calculations on. If you choose a fixed width then your height will vary for each unique width. For the example below all our images are to be reduced to 100 pixels wide, if it is already less than 100 pixels wide then the image is fine as it is.

    See the problem is that the fixed size is variable, depending on the source image, which is why this is more a math problem than a coding problem. If the image is wider than it is high, the fixed size will be the width; whereas if it's higher than it is wide, the fixed size will be height. This isn't a problem in the square /new/ image, but when you make the new image rectangular, it's adding a secondary level of complication in. When working in an image editor, it's easy to see what you have to do, it's just applying the math I'm having difficulty with. I was pretty good at math, but that was a while back.

    I think this is what you are asking because your code does properly re-scale all images (including rectangles) to 100x100, leaving the correct whitespace above and below, or to the left and the right of the rescaled image. What were you asking for?

    Always my problem, I can never explain what I'm looking for properly. See, at the moment, the replacement image is fixed to a square. Working out the aspects is a piece of widdle in this case, because I just slot in 100 wherever necessary and I'm done. However, if the image is rectangular - I'd like to have the option, because I'm picky - it complicates the process.

    I'll figure it out, I just need to put more thought into it... :)

    adam


  • Advertisement
  • Registered Users Posts: 944 ✭✭✭nahdoic


    ahh well that's easy too. What you should have said is that you want to set the final thumbnail width and height to be whatever you want. That is if i understand you right this time.

    This code is also working you can just copy and paste it in.

    [PHP]<?php

    // Final desired with and height of thumbnail

    $wf = 200;
    $hf = 100;

    // JPEG load error handler: if we can't load the JPEG, send a pretty image to say so!
    function loadJPEG($f)
    {
    $i = @ImageCreateFromJPEG($f);
    if (!$i) {
    $i = ImageCreate(600, 30);
    $b = ImageColorAllocate($i, 255, 255, 255);
    $t = ImageColorAllocate($i, 0, 0, 0);
    ImageFilledRectangle($i, 0, 0, 150, 30, $b);
    ImageString($i, 2, 5, 5, "Error loading '$f'", $t);
    ImageJPEG($i);
    exit();
    } else {
    return $i;
    }
    }

    // Load the original

    $i1 = loadJPEG("./images/$i");

    // Width & height of the ORIGINAL image
    $w1 = ImageSX($i1);
    $h1 = ImageSY($i1);

    // Create the new image
    $i2 = ImageCreate($wf, $hf);

    // White color fill
    $c = ImageColorAllocate($i2, 255, 255, 255);
    ImageFill($i2, 0, 0, $c);

    // resize ratios

    $wRatio=$wf/$w1;
    $hRatio=$hf/$h1;

    // If the ratios are the same we can resize straight.
    #if ($wRatio == $hRatio) {
    # ImageCopyResized($i2, $i1, 0, 0, 0, 0, $wf, $hf, $w1, $h1);
    #}

    // If the width Ratio is greater than the height ratio then we have to use the height Ratio.
    // This means the height will take up all the available pixels, and width will have some blank.
    if ($wRatio >= $hRatio) {
    $width = $hRatio*$w1;
    $height = $hf;
    $spacer = ($wf-$width)/2;
    ImageCopyResized($i2, $i1, $spacer, 0, 0, 0, $width, $height, $w1, $h1);
    }

    // If the height Ratio is greater than the width, then we have to use the width Ratio.
    else {
    $width = $wf;
    $height = $wRatio*$h1;
    $spacer = ($hf-$height)/2;
    ImageCopyResized($i2, $i1, 0, $spacer, 0, 0, $width, $height, $w1, $h1);
    }

    // Send the correct header
    header("Content-Type: image/jpeg");

    // Output the file
    ImageJPEG($i2);

    ?>[/PHP]


Advertisement