Proportionate scaling of an image using blt stretch.

● ARCHIVED · READ-ONLY
Started by Yin 6 posts View original ↗
  1. I need help trying to figure out if this is possible. I don't see any methods for it.

    My code is this, but I noticed that it stretches the whole image to fit the box.

    Code:
        image = Sprite_Base.new    image.visible = false    image.bitmap = Cache.image(image_name, 0)    rect = Rect.new(0, 0, image.bitmap.width, image.bitmap.height)    target = Rect.new(120, line_height * 2, 218, 143)    contents.stretch_blt(target, image.bitmap, rect, 255)

     

    Is it possible to scale proportionately? Is there a certain math for it that I need to know?
  2. I can't find it anymore. But I wrote that code once as well.

    Basically you check for the smallest possible scaling-axis and then scale the other axis with the same amount.

    It was something like:

    Code:
    max_scale_x = target.width - source.widthmax_scale_y = target.height - source.heighttotal_scale = [max_scale_x, max_scale_y].min# Now you know how much to scale  your image so now you can call the stretch_blt
  3. Napoleon said:
    I can't find it anymore. But I wrote that code once as well.

    Basically you check for the smallest possible scaling-axis and then scale the other axis with the same amount.

    It was something like:

    max_scale_x = target.width - source.widthmax_scale_y = target.height - source.heighttotal_scale = [max_scale_x, max_scale_y].min# Now you know how much to scale your image so now you can call the stretch_blt
    How does this tell you how much to scale your image? (which, presumably, is what Yin is asking)

    It is important to know how MUCH you can actually scale your image so that it doesn't go beyond the target rectangle, but we still have the problem of "how much to scale"
  4. Example:

    source image: 100x150

    target size: 200x200

    You want to scale the source image to the target size without losing the proportions.

    The previous pseudo-code:

    max_scale_x = target.width - source.widthmax_scale_y = target.height - source.heighttotal_scale = [max_scale_x, max_scale_y].minnow gives:
     

    max_scale_x = 200-100 # 100

    max_scale_y = 200-150 # 50

    total_scale = [100, 50].min # 50
    So the new image will be:

    target_rectangle = Rect.new(x, y, source.width + total_scale, source_height + total_scale) # target_rectangle is: x, y, 150, 200Now you should have the destination rectangle with the proportions kept intact.

    It is important to know how MUCH you can actually scale
    The "how much to scale" is: +50 in this example.

    Note: I'm not sure if this code works for scaling down as well. But scaling an image up should work in theory. But this code can be refactored and perhaps with some negative-checks or .abs() methods it will work for scaling down as well.
  5. Scaling down gives me 0 width/height. Images smaller than the box work well though. I'll try using that abs code to see how it works.

    I don't know why RM does not have this code by default since it's used in the database...

    EDIT:

    Thanks so much Napoleon. Using bits and pieces from your code and some internet code, I was able to make a fit to box method that everyone can use.

    It's more lengthy than the three lines you gave, but it ultimately serves its purpose. It gives the option to upscale things smaller than the box and auto downsizes bigger things to fit within the box. If anyone can shorten that (or make it better, feel free)

    Code:
    def fit_to_box(target_width, target_height, width, height, upscale = true)    # Don't Upscale    if width < target_width && height < target_height && upscale == false      return width, height    end        prop_width, prop_height = width, height    ratio = [width.to_f / height.to_f].min        if prop_width > target_height || prop_height < target_height    	prop_width = target_width    	prop_height = (prop_width / ratio).to_i    end    if prop_height > target_height || prop_width < target_height    	prop_height = target_height    	prop_width = (prop_height * ratio).to_i    end    return prop_width, prop_height  end
  6. I wrote a new one:

    class Rect  # Returns a new proportionally scaled Rect  def self.scale_proportional(source_rect, target_rect)    scale = [target_rect.width/source_rect.width.to_f, target_rect.height/source_rect.height.to_f].min    return Rect.new(source_rect.x, source_rect.y, source_rect.width * scale, source_rect.height * scale)  end  # Returns the scaling used and alters it's own width&height  def scale_proportional!(target_rect)    scale = [target_rect.width/self.width.to_f, target_rect.height/self.height.to_f].min    self.width = self.width * scale    self.height = self.height * scale    return scale  endendI tested it and it works with downscaling as well.

    Edit:

    I added it to my core script so I don't lose it myself next time :p .