/*
* MusicPage.java
*
* Copyright (C) 2006-2007 Gabriel Burca (gburca dash virtmus at ebixio dot com)
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package com.ebixio.virtmus;
import com.ebixio.virtmus.imgsrc.GenericImg;
import com.ebixio.virtmus.imgsrc.IcePdfImg;
import com.ebixio.virtmus.imgsrc.ImgSrc;
import com.ebixio.virtmus.imgsrc.PdfImg;
import com.ebixio.virtmus.options.Options;
import com.ebixio.virtmus.shapes.VmShape;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import javax.imageio.ImageIO;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.swing.event.ChangeListener;
/**
*
* @author Gabriel Burca <gburca dash virtmus at ebixio dot com>
*/
@XStreamAlias("page")
public abstract class MusicPage {
public Options.Rotation rotation = Options.Rotation.Clockwise_0;
private String name = null;
public static int thumbW = 130, thumbH = 200;
public volatile ImgSrc imgSrc;
private transient DraggableThumbnail thumbnail;
public transient Song song;
public transient boolean isDirty = false;
/** The AnnotTopComponent sets itself as a change listener so that we can
* tell it to repaint the annotation canvas when the SVG changes */
protected transient ChangeListener changeListener = null;
public abstract void clearAnnotations();
public abstract void popAnnotation();
public abstract void addAnnotation(VmShape shape);
public abstract void paintAnnotations(Graphics2D g2d);
@Override
public abstract MusicPage clone();
public abstract MusicPage clone(Song song);
public abstract void prepareToSave();
/** Creates a new instance of MusicPage
* @param song The song that this music page belongs to.
* @param sourceFile The file this music page came from
* @param opt The page number (in the case of a multi-page file)
*/
public MusicPage(Song song, File sourceFile, Object opt) {
this.song = song;
if (sourceFile.getName().toLowerCase().endsWith(".pdf")) {
int page = (Integer)opt;
imgSrc = new PdfImg(sourceFile, page);
//imgSrc = new IcePdfImg(sourceFile, page);
//imgSrc = new PdfViewImg(sourceFile, page);
} else {
imgSrc = new GenericImg(sourceFile);
}
}
/**
* The transient fields need to be initialized here. No constructor is called when
* the object is de-serialized.
* @param s The Song that this music page belongs to.
*/
public void deserialize(Song s) {
song = s;
}
public void setChangeListener(ChangeListener changeListener) {
this.changeListener = changeListener;
}
public void setDirty(boolean isDirty) {
this.thumbnail = null;
if (this.isDirty == isDirty) return;
//song.fire("pageSetDirty", this.isDirty, isDirty);
if (isDirty) song.setDirty(true);
this.isDirty = isDirty;
// If this change is not done by a NodeAction, we need to enable the actions here.
// SystemAction.get(SaveAllAction.class).setEnabled(true);
// SystemAction.get(SongSaveAction.class).setEnabled(true);
}
public boolean isDirty() {
return this.isDirty;
}
// /** When reading old files in (that don't have a rotation value) we need to
// * initialize rotation */
// private Object readResolve() {
// if (rotation == null) { rotation = MainApp.Rotation.Clockwise_0; }
// return this;
// }
public DraggableThumbnail getThumbnail() {
if (thumbnail == null) {
thumbnail = new DraggableThumbnail(thumbW, thumbH, getName());
thumbnail.setPage(this);
thumbnail.setPreferredSize(new Dimension(thumbW, thumbH));
thumbnail.setMinimumSize(new Dimension(thumbW, thumbH));
}
return thumbnail;
}
public File getSourceFile() {
return imgSrc.getSourceFile();
}
public void setSourceFile(File file) {
imgSrc.setSourceFile(file);
}
public void setName(String name) {
if (name.equals(this.name)) return;
this.name = name;
if (this.thumbnail != null) this.thumbnail.setName(name);
setDirty(true);
song.notifyListeners();
}
public String getName() {
if (name != null && name.length() > 0) return name;
if (imgSrc != null) {
return imgSrc.getName();
}
return "No name";
}
/**
* The index of this page in the song's page order.
* @return The 0-based index of this page in the song's page order.
*/
public int getPageNumber() {
return song.pageOrder.indexOf(this);
}
protected BufferedImage getImage(Dimension containerSize, Options.Rotation rotation, boolean fillSize) {
return imgSrc.getImage(containerSize, rotation, fillSize, this);
}
private RenderedOp rotate(RenderedOp srcImg, Options.Rotation rotation) {
if (rotation == Options.Rotation.Clockwise_0) return srcImg;
Interpolation interp = Interpolation.getInstance(Interpolation.INTERP_NEAREST);
ParameterBlock params = new ParameterBlock();
params.addSource(srcImg);
params.add(srcImg.getWidth()/2.0F);
params.add(srcImg.getHeight()/2.0F);
params.add(new Float(rotation.radians()));
params.add(interp);
return JAI.create("rotate", params);
}
/**
* Some sample code to save the page image to an external file. The image size
* will match the current display size and orientation.
*
* @param file The file to save the image to
* @param format The file format to use ("png", or "jpg")
*/
public void saveImg(final File file, final String format) {
Dimension displaySize = Utils.getScreenSize();
Dimension rotatedSize = Options.findInstance().screenRot.getSize(displaySize);
BufferedImage img = this.getImage(rotatedSize, Options.Rotation.Clockwise_0, false);
// Let's find out what the most efficient format is...
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
final BufferedImage imgToSave = gc.createCompatibleImage(img.getWidth(), img.getHeight(), Transparency.OPAQUE);
//final BufferedImage imgToSave = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
//final BufferedImage imgToSave = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2 = imgToSave.createGraphics();
boolean done = g2.drawImage(img, 0, 0, new ImageObserver() {
@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
if ((infoflags & ImageObserver.ALLBITS) > 0) {
try {
ImageIO.write(imgToSave, format, file);
} catch (Exception ex) {
}
return false;
}
return true;
}
});
if (done) {
try {
ImageIO.write(imgToSave, format, file);
} catch (Exception ex) { }
}
}
}