All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.sfac.gui.cmp.ImageComponent Maven / Gradle / Ivy

Go to download

This project is the core part of the Swing Framework and Components (SFaC). It contains the Swing framework classes and the graphical component classes.

The newest version!
/*-------------------------------------------------------------------------
 Copyright 2009 Olivier Berlanger

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 -------------------------------------------------------------------------*/
package net.sf.sfac.gui.cmp;


import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.MediaTracker;
import java.awt.image.ImageObserver;

import javax.swing.JComponent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * Component showing an image at the best fit without deformation. The image is resized (with the same scale in both X and Y
 * directions) to show at it's maximum size (within the space allowed by the component). If the image is smaller than this component
 * it is centered, the image is never enlarged.
 * 
 * @author Olivier Berlanger
 */
@SuppressWarnings("serial")
public class ImageComponent extends JComponent implements ImageObserver {

    private static final Dimension DEFAULT_SIZE = new Dimension(200, 250);

    public enum ImageFit {
        NONE, VERTICAL, HORIZONTAL, BOTH
    }

    private static Log log = LogFactory.getLog(ImageComponent.class);

    /** the image currently showing. */
    private Image image;
    /** Tracker used to load the image in background. */
    private MediaTracker track;
    /** Position and size of the image. */
    private int imgWidth;
    private int imgHeight;
    /** The scale of the painted image vs the real image size, always <= 1.0. */
    private float scale;
    private ImageFit fit = ImageFit.BOTH;


    public ImageComponent() {
        this(null);
    }


    public ImageComponent(Image im) {
        scale = 1.0f;
        track = new MediaTracker(this);
        if (im != null) setImage(im, false);
    }


    public void setImage(Image im) {
        setImage(im, true);
    }


    private void setImage(Image im, boolean needPaint) {
        if (image != null) track.removeImage(image);
        image = im;
        scale = 1.0f;
        if (image != null) {
            track.addImage(image, 0);
            imgWidth = image.getWidth(null);
            imgHeight = image.getHeight(null);
        } else {
            imgWidth = -1;
            imgHeight = -1;
        }
        if (needPaint) {
            invalidate();
            repaint();
        }
    }


    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Insets inset = getInsets();
        Dimension size = getSize();
        int cmpWidth = size.width - (inset.left + inset.right);
        int cmpHeight = size.height - (inset.top + inset.bottom);
        if (image != null) {
            waitForBits();
            if (track.statusID(0, true) != MediaTracker.ERRORED) {
                imgWidth = image.getWidth(null);
                imgHeight = image.getHeight(null);
                int visualImgWidth;
                int visualImgHeight;
                if ((imgWidth <= 0) || (imgHeight <= 0)) log.warn("Bad image size in paint : " + imgWidth + " x " + imgHeight);
                if (fit == ImageFit.NONE) {
                    visualImgWidth = Math.round(imgWidth * scale);
                    visualImgHeight = Math.round(imgHeight * scale);
                } else {
                    // resize the image
                    float ratio = ((float) imgWidth) / ((float) imgHeight);
                    if (imgWidth < cmpWidth) {
                        if (imgHeight < cmpHeight) {
                            visualImgWidth = imgWidth;
                            visualImgHeight = imgHeight;
                        } else {
                            visualImgWidth = (int) (cmpHeight * ratio);
                            visualImgHeight = cmpHeight;
                        }
                    } else {
                        if (imgHeight <= cmpHeight) {
                            visualImgWidth = cmpWidth;
                            visualImgHeight = (int) (cmpWidth / ratio);
                        } else {
                            int ssX = (int) (cmpHeight * ratio);
                            int ssY = (int) (cmpWidth / ratio);
                            if (ssY <= cmpHeight) {
                                visualImgWidth = cmpWidth;
                                visualImgHeight = ssY;
                            } else {
                                visualImgWidth = ssX;
                                visualImgHeight = cmpHeight;
                            }
                        }
                    }
                }
                // paint image (in the the background)
                int posX = (cmpWidth - visualImgWidth) / 2;
                int posY = (cmpHeight - visualImgHeight) / 2;
                g.drawImage(image, posX + inset.left, posY + inset.top, visualImgWidth, visualImgHeight, getBackground(), this);
                scale = ((float) visualImgHeight) / (float) imgHeight;
            } else {
                log.error("Image not properly loaded in tracker", new Exception("Stack dump"));
                g.setColor(getBackground());
                g.fillRect(inset.left, inset.top, cmpWidth, cmpHeight);
                scale = 1.0f;
            }
        }
    }


    @Override
    public Dimension getPreferredSize() {
        if ((image == null) || (imgWidth < 0) || (imgHeight < 0)) return DEFAULT_SIZE;
        if (fit != ImageFit.NONE) return DEFAULT_SIZE;
        return new Dimension(Math.round(imgWidth * scale), Math.round(imgHeight * scale));
    }


    @Override
    public Dimension getMinimumSize() {
        return getPreferredSize();
    }


    /**
     * Return the sizing factor of the displayed image (image size / displayed image size). Always less or equals to 1.0 as this
     * component never enlarge the images. Returns 1.0 if the size (or visual size) is not yet calculated.
     * 
     * @return float image size / displayed image size
     */
    public float getScale() {
        return scale;
    }


    public void setScale(float newScale) {
        scale = newScale;
    }


    public ImageFit getFit() {
        return fit;
    }


    public void setFit(ImageFit newFit) {
        fit = newFit;
    }


    /**
     * The image width in pixels.
     * 
     * @return the image width in pixels.
     */
    public int getImageWidth() {
        if (image == null) return 0;
        if (imgWidth <= 0) {
            waitForBits();
            imgWidth = image.getWidth(null);
        }
        return imgWidth;
    }


    /**
     * The image height in pixels.
     * 
     * @return the image height in pixels.
     */
    public int getImageHeight() {
        if (image == null) return 0;
        if (imgHeight <= 0) {
            waitForBits();
            imgHeight = image.getHeight(null);
        }
        return imgHeight;
    }


    public Dimension getImageSize() {
        Dimension result = null;
        if (image != null) {
            waitForBits();
            int imX = image.getWidth(null);
            int imY = image.getHeight(null);
            if ((imX <= 0) || (imY <= 0)) log.warn("Bad image size : " + imX + "," + imY);
            result = new Dimension(imX, imY);
        }
        return result;
    }


    private void waitForBits() {
        try {
            if ((image != null) && (track.statusID(0, true) == MediaTracker.LOADING)) track.waitForID(0);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("Exception while loading image: " + image, e);
        }
    }


    /**
     * Overridden to notify image producer to stop notifications (return false) for an old (animated) image.
     */
    @Override
    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
        if (isShowing() && isComponentImage(img)) return super.imageUpdate(img, infoflags, x, y, width, height);
        return false;
    }


    /**
     * Check if the given image is an image currently used by this component. Can be overriden by components managing more than one
     * image.
     */
    public boolean isComponentImage(Image img) {
        return (img == image);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy