/*
* Copyright 2013-2014 Odysseus Software GmbH
*
* 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 org.musicmount.builder.impl;
import java.awt.AWTError;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.musicmount.io.Resource;
import de.odysseus.ithaka.audioinfo.AudioInfo;
/**
* Generic asset parser based on.
*/
public abstract class AudioInfoAssetParser implements AssetParser {
static final Toolkit TOOLKIT;
static {
Toolkit toolkit = null;
try {
toolkit = Toolkit.getDefaultToolkit();
} catch (AWTError e) {
System.err.println("AWT toolkit not available: " + e);
} finally {
TOOLKIT = toolkit;
}
}
/**
* Do the magic...
* @param resource audio file
* @param imageOnly <code>true</code> if only interested in cover image
* @return audio info
* @throws Exception something went wrong
*/
protected abstract AudioInfo getAudioInfo(Resource resource, boolean imageOnly) throws Exception;
@Override
public Asset parse(Resource resource) throws Exception {
AudioInfo info = getAudioInfo(resource, false);
Asset asset = new Asset(resource);
asset.setAlbum(info.getAlbum());
asset.setAlbumArtist(info.getAlbumArtist());
asset.setArtist(info.getArtist());
asset.setArtworkAvailable(info.getCover() != null);
asset.setCompilation(info.isCompilation());
asset.setComposer(info.getComposer());
asset.setDiscNumber(info.getDisc() > 0 ? Integer.valueOf(info.getDisc()) : null);
asset.setDuration(info.getDuration() > 0 ? (int)((info.getDuration() + 500) / 1000) : null);
asset.setGenre(info.getGenre());
asset.setGrouping(info.getGrouping());
asset.setName(info.getTitle());
asset.setTrackNumber(info.getTrack() > 0 ? Integer.valueOf(info.getTrack()) : null);
asset.setYear(info.getYear() > 0 ? Integer.valueOf(info.getYear()) : null);
return asset;
}
/**
* Create image from bytes using ImageIO.
* @param cover image bytes
* @return buffered image
*/
BufferedImage toBufferedImageUsingImageIO(byte[] bytes) throws IOException {
try (InputStream data = new ByteArrayInputStream(bytes)) {
return ImageIO.read(data);
}
}
/**
* Create image from bytes using AWT toolkit.
* Seems to be faster than ImageIO...
* @param cover image bytes
* @return buffered image
*/
BufferedImage toBufferedImageUsingToolkit(byte[] bytes) throws IOException {
if (TOOLKIT == null) {
return null;
}
Image image = TOOLKIT.createImage(bytes);
MediaTracker mediaTracker = new MediaTracker(new Component() {
private static final long serialVersionUID = 1L;
});
mediaTracker.addImage(image, 0);
try {
mediaTracker.waitForID(0, 0);
} catch (InterruptedException e) {
return null;
}
if (mediaTracker.isErrorID(0)) { // error -> use ImageIO
throw new IOException("Failed to load toolkit image");
} else {
BufferedImage bufferedImage =
new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
image.flush();
return bufferedImage;
}
}
@Override
public BufferedImage extractArtwork(Resource resource) throws Exception {
byte[] cover = getAudioInfo(resource, true).getCover();
if (cover != null) {
BufferedImage bufferedImage = null;
try {
bufferedImage = toBufferedImageUsingToolkit(cover);
} catch (Throwable e) {
// ignore
}
if (bufferedImage == null) {
bufferedImage = toBufferedImageUsingImageIO(cover);
}
return bufferedImage;
}
return null;
}
}