Fitting an Image to its Frame

From Scribus Wiki
Jump to: navigation, search
This article is part of the Scripts series.

We have some built-in functions in Scribus to Adjust Image to Frame, and also Adjust Frame to Image. What if you have a situation where you have a frame of a set size, and must fill it, even though you end up cropping the edge a bit? It's certainly possible to do, but a bit fiddly.

Here is a script that will make sure an image fills either the height or width, by your choice. It does this by temporarily expanding the frame, calling setScaleImageToFrame to say to scale to the frame, then immediately calls the function again to say don't scale to the frame. After this, the frame is returned to its original dimensions, and since its in Free Scaling mode, the image scale stays the same.

This may be hard to understand verbally, but will be obvious once you run the script. If you make a mistake in the direction, just run the script again.

fitimage2frame.py

#!/usr/bin/env python
# -*- coding: utf-8  -*-

# ****************************************************************************
#  This program is free software; you can redistribute it and/or modify 
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# 
# ****************************************************************************


"""

© 2015 Gregory Pittman

fitimage2frame.py

USAGE

After selecting an image frame with image loaded, run script.
There is one dialog to choose whether to fit to Height (default) or width. Note that typing in anything
other than Height will fit to width.
It doesn't matter if you have or haven't selected Adjust Image to Frame prior to running the script.

"""

try:
    import scribus
except ImportError:
    print "Unable to import the 'scribus' module. This script will only run within"
    print "the Python interpreter embedded in Scribus. Try Script->Execute Script."
    sys.exit(1)


if scribus.selectionCount() != 1:
    scribus.messageBox('Selection Count', "You must have a frame selected",
                       scribus.ICON_WARNING, scribus.BUTTON_OK)
    sys.exit(2)

frame1 = scribus.getSelectedObject()

ftype1 = scribus.getObjectType(frame1)
if (ftype1 != "ImageFrame"):
    scribus.messageBox('Object Type', "Selected object must be an image frame",
                       scribus.ICON_WARNING, scribus.BUTTON_OK)
    sys.exit(2)

fitwhich = scribus.valueDialog("Fit to Height?",'Change to anything else to fit to width',"Height")

scribus.setRedraw(False)
frameW, frameH = scribus.getSize(frame1)

if (fitwhich == "Height"):
    scribus.sizeObject(frameW*3, frameH, frame1)
    scribus.setScaleImageToFrame(1,1,frame1)
    scribus.setScaleImageToFrame(0,1,frame1)
    scribus.sizeObject(frameW, frameH, frame1)

else:
    scribus.sizeObject(frameW, frameH*3, frame1)
    scribus.setScaleImageToFrame(1,1,frame1)
    scribus.setScaleImageToFrame(0,1,frame1)
    scribus.sizeObject(frameW, frameH, frame1)

scribus.setRedraw(True)

Notes

After the script runs, you will see that the X-Pos, Y-Pos of the image is at the left upper corner of the frame, so you may want to move in the appropriate direction to best show the part of the image you wish to display.

You could change the valueDialog so it uses "Yes" for the response, but I like the visual reminder of what the default is. I'm also lazy, so I don't want to have to carefully spell "Width" or "width", then write the logic to cover errors. There are only two choices here, either the default, or something else, in this case width. You can just delete the default to get the same result.

I choose to expand the affected dimension by a factor of 3 to cover most situations, but of course this may not work with all images. Make it bigger if you need to. Notice that we don't have to worry about whether we're using integer or float math, since we just replace the altered value with the original.

What happens if you have an image frame and forgot to load the image? Answer: no error generated, no end change in frame.

fitimage2frame_v2.py

Here is another version, taking a cue from Christian Mandel on the mail list. This time, we first scale the image frame, but not proportionally, then take the higher scale value (X-scale vs. Y-scale) as the value to assign in both directions. An advantage of this method is that will work regardless of the proportions of the image.

#!/usr/bin/env python
# -*- coding: utf-8  -*-

# ****************************************************************************
#  This program is free software; you can redistribute it and/or modify 
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# 
# ****************************************************************************


"""

© 2015 Gregory Pittman

fitimage2frame_v2.py

USAGE
This script will resize an image to the smallest scale it can be, yet fill
the frame completely in both directions.

After selecting an image frame with image loaded, run script.

It doesn't matter if you have or haven't selected Adjust Image to Frame prior to running the script.

"""

try:
    import scribus
except ImportError:
    print "Unable to import the 'scribus' module. This script will only run within"
    print "the Python interpreter embedded in Scribus. Try Script->Execute Script."
    sys.exit(1)


if scribus.selectionCount() != 1:
    scribus.messageBox('Selection Count', "You must have a (single) frame selected",
                       scribus.ICON_WARNING, scribus.BUTTON_OK)
    sys.exit(2)

frame1 = scribus.getSelectedObject()

ftype1 = scribus.getObjectType(frame1)
if (ftype1 != "ImageFrame"):
    scribus.messageBox('Object Type', "Selected object must be an image frame",
                       scribus.ICON_WARNING, scribus.BUTTON_OK)
    sys.exit(2)

scribus.setRedraw(False)

scribus.setScaleImageToFrame(1,0,frame1)

xscale, yscale = scribus.getImageScale(frame1)
scribus.setScaleImageToFrame(0,1,frame1)

if (xscale > yscale):
    scribus.setImageScale(xscale, xscale, frame1)
    
else:
    scribus.setImageScale(yscale, yscale, frame1)
    
scribus.setRedraw(True)

Notes

Notice that under Usage, I say that the image will be resized to the "smallest scale", yet in the script I choose the larger scaling. This is because, if you could see the image at that point you would see that it's not keeping the aspect ratio of the image file. That is the point of the script, to make sure the frame is completely filled, and the aspect ratio is correct.

You might also look at http://wiki.scribus.net/canvas/Scale_an_Image_to_Fill_a_Frame_Proportionally which is very similar. It doesn't have the error-checking you see here, but has the ability to select a number of frames at once, then perform the resizing in a loop.