package util;
//----- JDK Imports ------------------------------------------------------------
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.lang.reflect.Array;
import java.util.ArrayList;
//----- Quicktime Imports ------------------------------------------------------
import quicktime.QTException;
import quicktime.qd.Pict;
import quicktime.std.StdQTConstants;
import quicktime.std.movies.Movie;
import quicktime.std.movies.Track;
//----- SISC Imports -----------------------------------------------------------
import sisc.data.Pair;
import sisc.interpreter.SchemeException;
//----- Phoenix Imports --------------------------------------------------------
import util.ImageUtils;
/**
* 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.
* @author Pan, Jiabei; Rebelsky, Samuel; Whisenhunt, Heather
* @author Glimmer Labs
* @version 0.2.0
*/
public class Kluberizer
{
/*---------*------------------------------------------------------------------
* Methods *
*---------*/
/**
* Resize a Pict
*
* @param pic Pict to be resized
* @param direction Direction to squish: 0,2=vertical; 1,3=horizontal
* @param percent Percent of current pict size to which to squish
* @return buff Squished frame
*/
public BufferedImage squishFrame(Pict pic, int direction, float percent)
{
/*
* Directions (dir)
* 0
* +----+
*3 | | 1
* +----+
* 2
*/
// inspired by
// http://forum.java.sun.com/thread.jspa?threadID=633983&messageID=3684869
BufferedImage buff = ImageUtils.makeJimage(pic);
int actualWidth = pic.getPictFrame().getWidth();
int actualHeight = pic.getPictFrame().getHeight();
// retain one original dimension, change the other to correct percent
int resultWidth = actualWidth;
int resultHeight = actualHeight;
AffineTransform aff = null;
if ((direction == 0) || (direction == 2))
{
resultHeight = (int)Math.floor(actualHeight * percent);
aff = AffineTransform.getScaleInstance(1, percent);
} // if ((direction == 0) || (dirction == 2))
else if ((direction == 1) || (direction == 3))
{
resultWidth = (int)Math.floor(actualWidth * percent);
aff = AffineTransform.getScaleInstance(percent, 1);
} // else if ((direction == 1) || (direction == 3))
BufferedImage nbi = new BufferedImage(resultWidth, resultHeight,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = nbi.createGraphics();
g2.setTransform(aff);
g2.drawImage(buff, 0, 0, null);
return nbi;
} // squishFrame(Pict, int, float)
/**
* Glue two BufferedImages together into a Pict
*
* @param buff1 BufferedImage to glue
* @param buff2 BufferedImage to glue
* @param direction Direction to glue buffs: 0 = buff1 on top;
* 1 = buff1 on right; 2 = buff1 on bottom;
* 3 = buff1 on left
* @param width Width of resulting Pict
* @param height Height of resulting Pict
* @return pic Pict composed of buff1 and buff2
*/
public Pict glueFrame(BufferedImage buff1, BufferedImage buff2, int direction,
int width, int height)
{
/*
* Directions (dir)
* 0
* +----+
*3 | | 1
* +----+
* 2
*/
BufferedImage buff = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
WritableRaster ras = buff.getRaster();
WritableRaster ras1 = buff1.getRaster();
WritableRaster ras2 = buff2.getRaster();
int x1 = 0;
int y1 = 0;
int x2 = 0;
int y2 = 0;
switch (direction)
{
case 0 :
y2 = ras1.getHeight();
break;
case 1 :
x1 = ras2.getWidth();
break;
case 2 :
y1 = ras2.getHeight();
break;
case 3 :
x2 = ras1.getWidth();
break;
} // switch (direction)
ras.setDataElements(x1, y1, ras1);
ras.setDataElements(x2, y2, ras2);
return ImageUtils.makeFrame(buff);
} // glueFrame(BufferedImage, BufferedImage, int, int, int)
/**
* Kluberize one frame
*
* @param pic Pict to be Kluberized
* @param direction Direction to Kluberize: 0 = top; 1 = right; 2 = bottom;
* 3 = right
* @param percent Percent of result image occupied by frame in direction
* @return result Kluberized pic
*/
public Pict kluberizeOne(Pict pic, int direction, float percent)
{
if (((int)Math.floor(pic.getPictFrame().getHeight() * percent) == 0)
|| ((int)Math.floor(pic.getPictFrame().getWidth() * percent) == 0))
{
return pic;
} // if (((int)Math.floor(pict.getPictFrame().getHeight() * percent) ...
else
{
BufferedImage squished1 = squishFrame(pic, direction, percent);
BufferedImage squished2 = squishFrame(pic, direction, 1 - percent);
Pict ret = glueFrame(squished1, squished2, direction,
pic.getPictFrame().getWidth(), pic.getPictFrame().getHeight());
return ret;
} // else
} // kluberizeOne(Pict, int, float)
/**
* Kluberize a complete cycle of frames
*
* @param pics Array of picts in cycle to be Kluberized
* @param direction Direction to Kluberize: 0 = top; 1 = right; 2 = bottom;
* 3 = right
* @return result Kluberized cycle
*/
public Pict[] kluberizeCycle(Pict[] pics, int direction)
{
int length = Array.getLength(pics);
float step = (float) 0.5 / length;
float currentPer = 0;
for (int i = 0; i < length; i++)
{
currentPer = currentPer + step;
pics[i] = kluberizeOne(pics[i], direction, currentPer);
} // for
return pics;
} // kluberizeCycle(Pict[], int)
/**
* Kluberize a movie
*
* @param mov Movie to be Kluberized
* @param direction Direction to Kluberize: 0 = top; 1 = right; 2 = bottom;
* 3 = right
* @param time Time of Kluberization cycle
* @return movie Kluberized movie
* @throws SchemeException
*/
public Movie kluberizeMovie(Movie mov, int direction, float time)
throws SchemeException
{
ArrayList<Pict> result = new ArrayList<Pict>();
float length = 0;
try
{
length = mov.getDuration() / mov.getTimeScale();
int cycles = (int)Math.ceil(length / time);
// for each cycle
for (int i = 0; i < cycles - 1; i++)
{
Pict[] thisCycle = MovieUtils.getAllFrames(mov, i * time,
(i + 1) * time);
// number of times to process each cycle
for (int j = 0; j < i; j++)
{
// for each frame in the cycle
for (int k = 0; k < Array.getLength(thisCycle); k++)
{
thisCycle[k] = kluberizeOne(thisCycle[k], direction, 0.5f);
} // for
} // for
thisCycle = kluberizeCycle(thisCycle, direction);
for (int l = 0; l < Array.getLength(thisCycle); l++)
{
result.add(thisCycle[l]);
} // for
} // for
Pict[] thisCycle = MovieUtils.getAllFrames(mov, (cycles - 1) * time,
length);
// for each cycle
for (int j = 0; j < cycles - 1; j++)
{
// for each frame in cycle
for (int k = 0; k < Array.getLength(thisCycle); k++)
{
thisCycle[k] = kluberizeOne(thisCycle[k], direction, 0.5f);
// user terminated execution
if (Thread.interrupted())
{
throw new SchemeException(new Pair(), null, null);
} // if (Thread.interrupted())
} // for
} // for
// for the last cycle
thisCycle = kluberizeCycle(thisCycle, direction);
for (int l = 0; l < Array.getLength(thisCycle); l++)
{
result.add(thisCycle[l]);
} // for
Pict[] res = new Pict[0];
// copy the audio into the new movie
Track sound = mov.getIndTrackType(1,
StdQTConstants.audioMediaCharacteristic,
StdQTConstants.movieTrackCharacteristic);
Movie video = MovieUtils.compileFrames(result.toArray(res),
(int)MovieUtils.countFrames(mov, 0, 1), mov.getTimeScale());
if (sound != null)
{
MovieUtils.addAudioTrack(sound, video);
} // if (sound != null)
return video;
} // try
catch (QTException qte)
{
qte.printStackTrace();
} // catch (QTException)
return null;
} // kluberizeMovie(Movie, int, float)
} // class Kluberizer