package util;
//----- JDK Imports ------------------------------------------------------------
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.ImageIcon;
//----- Quicktime Imports ------------------------------------------------------
import quicktime.QTException;
import quicktime.app.view.GraphicsImporterDrawer;
import quicktime.app.view.QTImageProducer;
import quicktime.io.QTFile;
import quicktime.qd.Pict;
import quicktime.std.StdQTConstants;
import quicktime.std.StdQTException;
import quicktime.std.image.GraphicsImporter;
import quicktime.std.movies.Movie;
import quicktime.std.movies.media.DataRef;
//----- Phoenix Imports --------------------------------------------------------
import controller.PhoenixController;
/**
* Video Phoenix
* Version 0.2.0
* Copyright (c) 2007 Lunderskov, Ian; Pan, Jiabei; Rebelsky, Samuel;
* Whisenhunt, Heather; Young, Ian; Zuleta Benavides, Luis.
* All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This class has all static methods to help manage types for the Frame class.
* Since all classes in QT for Java are Final, when we refer to Frames, we mean
* quicktime.qd.Pict objects.
*
* @author Lunderskov, Ian; Pan, Jiabei; Rebelsky, Samuel; Whisenhunt, Heather;
* Young, Ian; Zuleta Benavides, Luis
* @author Glimmer Labs
* @version 0.2.0
*
*/
public class ImageUtils
{
/*---------*------------------------------------------------------------------
* Methods *
*---------*/
/**
* Get an icon from a movie
*
* @param mov Movie to make icon for
*/
public static ImageIcon getIcon(Movie mov)
{
Pict pic = null;
Image image = null;
try
{
// if no visual track, substitute another image
if ((mov.getBounds().getHeight() == 0)
|| (mov.getBounds().getWidth() == 0))
{
try
{
pic = ImageUtils.pictFromFile(PhoenixController.getImage(
"noimage.bmp"));
} // try
catch (Exception e)
{
e.printStackTrace();
} // catch (Exception)
} // if ((mov.getBounds().getHeight() == 0) ...
else
{
try
{
// if mov is less than 2 seconds long
if (2 > (mov.getDuration() / mov.getTimeScale()))
{
pic = mov.getPict(0);
} // if (2 > (mov.getDuration() / mov.getTimeScale()))
else
{
pic = mov.getPict(2 * mov.getTimeScale());
} // else
} // try
catch (Exception e)
{
e.printStackTrace();
} // catch (Exception)
} // else
} // try
catch (StdQTException stdqte)
{
stdqte.printStackTrace();
} // catch (StdQTException)
try
{
image = util.ImageUtils.makeJimage(pic, 100, 75);
} // try
catch (Exception e)
{
e.printStackTrace();
} // catch (Exception)
ImageIcon icon = new ImageIcon(image);
return icon;
} // getIcon(Movie)
/**
* Get a WritableRaster from a Pict
*
* @param pic Pict to get WritableRaster
* @return raster WritableRaster of pic
*/
public static WritableRaster makeRaster(Pict pic)
{
BufferedImage image = ImageUtils.makeJimage(pic);
return image.getRaster();
} // makeRaster(Pict)
/**
* Get a WritableRaster from a movie at a specified time
*
* @param mov Movie to get WritableRaster
* @param time Time in movie to retrieve WritableRaster
* @return raster WritableRaster of the frame in mov at time
*/
public static WritableRaster makeRaster(Movie mov, float time)
{
Pict pic = MovieUtils.getMovieFrame(mov, time);
BufferedImage image = ImageUtils.makeJimage(pic);
return image.getRaster();
} // makeRaster(Movie, float)
/**
* Get a BufferedImage from an Image
*
* @param image Image to be converted
* @return bufferedImage BufferedImage from image
*/
public static BufferedImage makeBufferedImage(Image image)
{
return makeBufferedImage(image, BufferedImage.TYPE_INT_RGB);
} // makeBufferedImage(Image)
/**
* Get a BufferedImage from an Image with a certain type
*
* @param image Image to be converted
* @param imageType Type of image
* @return bufferedImage BufferedImage from image
*/
public static BufferedImage makeBufferedImage(Image image, int imageType)
{
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null),
image.getHeight(null), imageType);
Graphics2D g2 = bufferedImage.createGraphics();
g2.drawImage(image, null, null);
return bufferedImage;
} // makeBufferedImage(Image, int)
/**
* Get a BufferedImage from a Pict
*
* @param pic Pict to be converted
* @return buff BufferedImage from Pict
*/
public static BufferedImage makeJimage(Pict pic)
{
BufferedImage image = null;
try
{
image = makeBufferedImage(makeJimage (pic, pic.getPictFrame().getWidth(),
pic.getPictFrame().getHeight()));
} // try
catch (QTException qte)
{
qte.printStackTrace();
} // catch (QTException)
return image;
} // makeJimage(Pict)
/**
* Get an Image from a Pict
*
* @param pic Pict to be converted
* @param width Width of pic
* @param height Height of pic
* @return image Image from pic
* @throws QTException
*/
// Adapted from
// Chris Adamson, QuickTime for Java: A Developer's Notebook
// Published by O'Reilly, 2005
// p. 94
public static Image makeJimage(Pict pic, int width, int height)
throws QTException
{
// graphics importer and a graphicsImporterDrawer
GraphicsImporter gi = new GraphicsImporter(
StdQTConstants.kQTFileTypePicture);
GraphicsImporterDrawer gid = new GraphicsImporterDrawer(gi);
// Add 512 byte header so the grapics importer will think that it's dealing
// with a pict file
byte[] newPictBytes = new byte[pic.getSize() + 512];
pic.copyToArray(0, newPictBytes, 512, newPictBytes.length - 512);
pic = new Pict(newPictBytes);
// export the pict
DataRef ref = new DataRef(pic, StdQTConstants.kDataRefQTFileTypeTag,
"PICT");
gi.setDataReference(ref);
Dimension dim = new Dimension(width, height);
QTImageProducer ip = new QTImageProducer(gid, dim);
// convert to java.awt.Image and then to image icon
Image image = Toolkit.getDefaultToolkit().createImage(ip);
return image;
} // makeJimage(Pict, int, int)
/**
* Get a Pict from an Image
*
* @param image Image to be converted
* @return pic Pict from Image
*/
public static Pict makeFrame(Image image)
{
BufferedImage buff = makeBufferedImage(image);
return makeFrame(buff);
} // makeFrame(Image)
/**
* Get a Pict from a BufferedImage
*
* @param buff BufferedImage to be converted
* @return pic Pict from BufferedImage
*/
public static Pict makeFrame(BufferedImage buff)
{
Pict pic = null;
try
{
File tempfile = File.createTempFile("Frame2b", ".jpg");
makeJpegFile(buff, tempfile.getPath());
pic = pictFromFile(tempfile);
tempfile.delete();
} // try
catch (Exception ioe)
{
ioe.printStackTrace();
} // catch (Exception)
return pic;
} // makeFrame(BufferedImage)
/**
* Save an Image as a JPEG
*
* @param image Image to be saved
* @param path Where JPEG will be saved
*/
public static void makeJpegFile(Image image, String path)
{
BufferedImage buff = makeBufferedImage(image);
makeJpegFile(buff, path);
} // makeJpegFile(Image, String)
/**
* Save a BufferedImage as a JPEG
*
* @param buff BufferedImage to be saved
* @param path Where JPEG will be saved
*/
public static void makeJpegFile(BufferedImage buff, String path)
{
try
{
File file = new File(path);
FileOutputStream out = new FileOutputStream(file);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buff);
param.setQuality(1.0f, true);
encoder.setJPEGEncodeParam(param);
encoder.encode(buff);
out.close();
} // try
catch (IOException ioe)
{
ioe.printStackTrace();
} // catch (IOException)
} // makeJpegFile(BufferedImage, String)
/**
* Get a Pict from a file
*
* @param name Name of file where Pict is stored
* @return pic Pict in file
* @throws Exception
*/
public static Pict pictFromFile(String name)
throws Exception
{
return ImageUtils.pictFromFile(new File(name));
} // pictFromFile(String)
/**
* Get a Pict from a file
*
* @param file File where Pict is stored
* @return pic Pict in file
* @throws Exception
*/
public static Pict pictFromFile(File file)
throws Exception
{
return ImageUtils.pictFromFile(new QTFile(file));
} // pictFromFile(File)
/* get a pict from a QTFile */
private static Pict pictFromFile(QTFile file)
throws QTException
{
GraphicsImporter gi = new GraphicsImporter(file);
return gi.getAsPicture();
} // pictFromFile(QTFile)
/**
* Get a pixel from a movie
*
* @param mov Movie to get pixel
* @param time Time in movie
* @param channel Color channel (e.g. "rgb", "hsv")
* @param x X-coordinate in movie frame
* @param y Y-coordinate in movie frame
* @return pixel Pixel data from specified location
*/
public static int[] getPixel(Movie mov, float time, String channel, int x,
int y)
{
Pict pic = MovieUtils.getMovieFrame(mov, time);
BufferedImage image = util.ImageUtils.makeJimage(pic);
WritableRaster raster = image.getRaster();
return ImageUtils.getPixel(raster, channel, x, y);
} // getPixel(Movie, float, String, int, int)
/**
* Get a pixel from a WritableRaster
*
* @param raster Raster
* @param channel Color channel (e.g. "RGB", "HSV")
* @param x X-coordinate in raster
* @param y Y-coordinate in raster
* @return pixel Pixel data from specified location
*/
public static int[] getPixel(WritableRaster raster, String channel, int x,
int y)
{
int[] data = new int[4];
raster.getPixel(x, y, data);
if (channel.equalsIgnoreCase("rgb"))
{
return data;
} // if (channel.equalsIgnoreCose("rgb"))
else
{
return PhoenixController.getHistogramController().RGBtoHSV(data);
} // else
} // getPixel(WritableRaster, String, int, int)
/**
* Paint text on a pict
*
* @param pic Pict to be painted
* @param text Text to be painted on pict
* @param fontName Font name (e.g., "Monospaced", "SansSerif", "Serif")
* @param fontOptions Font style (e.g., "bold", "bolditalic", "italic")
* @param fontSize Font size
* @param color RGB values for color (e.g., [0,0,0] for black)
* @param x X-coordinate on pict of lower left corner of text block
* @param y Y-coordinate on pict of lower left corner of text block
* @return result Pict with text
*/
public static Pict paintText(Pict pic, String text, String fontName,
String fontOptions, int fontSize, int[] color, int x, int y)
{
BufferedImage bimg = ImageUtils.makeJimage(pic);
Graphics2D g2d = bimg.createGraphics();
Font f = null;
if (fontOptions.equalsIgnoreCase("bold"))
{
f = new Font(fontName, Font.BOLD, fontSize);
} // if (fontOptions.equalsIgnoreCase("bold"))
else if (fontOptions.equalsIgnoreCase("italic"))
{
f = new Font(fontName, Font.ITALIC, fontSize);
} // else if (fontOptions.equalsIgnoreCase("italic"))
else if (fontOptions.equalsIgnoreCase("bolditalic"))
{
f = new Font(fontName, Font.BOLD + Font.ITALIC, fontSize);
} // else if (fontOptions.equalsIgnoreCase("bolditalic"))
else
{
f = new Font(fontName, Font.PLAIN, fontSize);
} // else
g2d.setFont(f);
g2d.setPaint(new Color(color[0], color[1], color[2]));
g2d.drawString(text, x, y);
Pict result = util.ImageUtils.makeFrame(bimg);
return result;
} // paintText(Pict, String, String, String, int, int[], int, int)
/**
* Get color data for all pixels in a given range
*
* @param pic Pict with pixels of interest
* @param channel Color channel (e.g., "rgb", "hsv")
* @param left Left edge of range of interest (inclusive)
* @param right Right edge of range of interest (exclusive)
* @param top Top edge of range of interest (inclusive)
* @param bottom Bottom edge of range of interest (exclusive)
* @return pixels Pixel data from given range
*/
public static int[][] getAllPixels(Pict pic, String channel, int left,
int right, int top, int bottom)
{
WritableRaster raster = ImageUtils.makeRaster(pic);
int[][] all = new int[(right - left) * (bottom - top)][3];
int[] data = new int[3];
for (int i = left; i < right; i++)
{
for (int j = top; j < bottom; j++)
{
data = ImageUtils.getPixel(raster, channel, i, j);
all[(i - left) + (j - top) * (right - left)][0] = data[0];
all[(i - left) + (j - top) * (right - left)][1] = data[1];
all[(i - left) + (j - top) * (right - left)][2] = data[2];
} // for
} // for
return all;
} // getAllPixels(Pict, String, int, int, int, int)
/**
* Get all pixel data for pict
*
* @param pic Pict to get pixel data for
* @param channel Color channel (e.g., "rgb", "hsv")
* @return pixels Pixel data for pict
*/
public static int[][] getAllPixels(Pict pic, String channel)
{
int left = 0;
int top = 0;
int bottom = pic.getPictFrame().getHeight();
int right = pic.getPictFrame().getWidth();
return ImageUtils.getAllPixels(pic, channel, left, right, top, bottom);
} // getAllPixels(Pict, String)
/**
* Set every pixel in a region to be a specified color
*
* @param pic Pict to be modified
* @param top Top edge of range of interest (inclusive)
* @param bottom Bottom edge of range of interest (exclusive)
* @param left Left edge of range of interest (inclusive)
* @param right Right edge of range of interest (exclusive)
* @param red Red value of key color
* @param green Green value of key color
* @param blue Blue value of key color
* @return result pic with every pixel in region set to key color
*/
public static Pict setRegionColor(Pict pic, int top, int bottom, int left,
int right, int red, int green, int blue)
{
Pict result = pic;
try
{
BufferedImage image = ImageUtils.makeJimage(pic);
int width = right - left;
int height = bottom - top;
int[] pixels = new int[width * height];
image.getRGB(left, top, width, height, pixels, 0, width);
int hexColor = (red << 16) | (green << 8) | (blue);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
pixels[i * width + j] =
(pixels[i * width + j] & 0xFF000000) | hexColor;
} // for
} // for
image.setRGB(left, top, width, height, pixels, 0, width);
result = ImageUtils.makeFrame(image);
} // try
catch (Exception e)
{
e.printStackTrace();
} // catch (Exception)
return result;
} // setRegionColor(Pict, int, int, int, int, int, int, int)
} // class ImageUtils