From eb02ca7665f9591647d990a1ff1eef05c359b7e6 Mon Sep 17 00:00:00 2001 From: Nathan Cannon Date: Tue, 8 Mar 2016 17:01:24 +0000 Subject: [PATCH] Refactored album art retrieval to prevent repeat loading of the same image into memory. --- .../java/musicplayer/AlbumArtExtractor.java | 84 +++++++++++++++++++ src/main/java/musicplayer/db/Gateway.java | 4 +- .../musicplayer/model/ExtractedMetadata.java | 48 ----------- 3 files changed, 87 insertions(+), 49 deletions(-) create mode 100644 src/main/java/musicplayer/AlbumArtExtractor.java diff --git a/src/main/java/musicplayer/AlbumArtExtractor.java b/src/main/java/musicplayer/AlbumArtExtractor.java new file mode 100644 index 0000000..124715f --- /dev/null +++ b/src/main/java/musicplayer/AlbumArtExtractor.java @@ -0,0 +1,84 @@ +package musicplayer; + +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.tag.Tag; +import org.jaudiotagger.tag.TagException; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; + +public final class AlbumArtExtractor { + + private static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)"; + + /** + * Get the album art for a song file. + * @param songFile File from which to get album art data + * (Data is either extracted from file metadata or an image in the same folder). + * @return Album art as a byte array. + */ + public static byte[] getImageData(File songFile){ + Tag audioTags = null; + try { + audioTags = AudioFileIO.read(songFile).getTag(); + } catch (CannotReadException | IOException | ReadOnlyFileException | TagException | InvalidAudioFrameException e) { + return null; + } + byte[] tmpArt = null; + try { + tmpArt = audioTags.getFirstArtwork().getBinaryData(); + BufferedImage image = ImageIO.read(new ByteArrayInputStream(tmpArt)); + tmpArt = convertImageToBytes(image); + } catch (IOException | NullPointerException e) { + try { + Path dir = songFile.toPath().getParent(); + Optional imageFile = Files.walk(dir).filter(x -> x.toString().matches(albumArtRegex)).findFirst(); + if (imageFile.isPresent()) { + Image actualImage = ImageIO.read(imageFile.get().toFile()); + tmpArt = convertImageToBytes(actualImage); + } + } catch (NullPointerException | IOException ignored) {} + } + return tmpArt; + } + + /** + * Convert an Image into its' byte array representation. + * @param image Image to convert. + * @return image as byte[]. + */ + private static byte[] convertImageToBytes(Image image){ + int imageScaleToSize = 50; + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){ + ImageIO.write(convertToBufferedImage(image.getScaledInstance(imageScaleToSize, imageScaleToSize, Image.SCALE_SMOOTH)), "jpg", baos); + baos.flush(); + return baos.toByteArray(); + } catch (IOException e) { return null; } + } + + /** + * Convert an Image to a BufferedImage. + * @param image Source image. + * @return image as BufferedImage. + */ + private static BufferedImage convertToBufferedImage(Image image) { + BufferedImage newImage = new BufferedImage( + image.getWidth(null), image.getHeight(null), + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = newImage.createGraphics(); + g.drawImage(image, 0, 0, null); + g.dispose(); + return newImage; + } +} diff --git a/src/main/java/musicplayer/db/Gateway.java b/src/main/java/musicplayer/db/Gateway.java index ab19ccc..d8403f4 100644 --- a/src/main/java/musicplayer/db/Gateway.java +++ b/src/main/java/musicplayer/db/Gateway.java @@ -1,10 +1,12 @@ package musicplayer.db; +import musicplayer.AlbumArtExtractor; import musicplayer.model.*; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.criterion.Restrictions; +import java.io.File; import java.util.List; import java.util.Map; import java.util.Optional; @@ -94,7 +96,7 @@ public class Gateway { session.beginTransaction(); Optional albumObj = getOneAlbum(metadata.album); if (!albumObj.isPresent()) { - Album album = new Album(metadata.album, metadata.artwork); + Album album = new Album(metadata.album, AlbumArtExtractor.getImageData(new File(metadata.songFile))); albumObj = Optional.of(album); } Optional artistObj = getOneArtist(metadata.artist); diff --git a/src/main/java/musicplayer/model/ExtractedMetadata.java b/src/main/java/musicplayer/model/ExtractedMetadata.java index adac0e3..ca5350d 100644 --- a/src/main/java/musicplayer/model/ExtractedMetadata.java +++ b/src/main/java/musicplayer/model/ExtractedMetadata.java @@ -24,11 +24,8 @@ public class ExtractedMetadata { public final String genre; public final String songFile; public final String trackNumber; - public final byte[] artwork; public final String discNumber; - private static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)"; - /** * @param audioTags jaudiotagger tag data. * @param songFile Location of the song file on the filesystem. @@ -41,51 +38,6 @@ public class ExtractedMetadata { this.genre = audioTags.getFirst(FieldKey.GENRE); this.discNumber = audioTags.getFirst(FieldKey.DISC_NO); this.songFile = songFile.getAbsolutePath(); - byte[] tmpArt = null; - try { - tmpArt = audioTags.getFirstArtwork().getBinaryData(); - BufferedImage image = ImageIO.read(new ByteArrayInputStream(tmpArt)); - tmpArt = convertImageToBytes(image); - } catch (IOException | NullPointerException e) { - try { - Path dir = songFile.toPath().getParent(); - Optional imageFile = Files.walk(dir).filter(x -> x.toString().matches(albumArtRegex)).findFirst(); - if (imageFile.isPresent()) { - Image actualImage = ImageIO.read(imageFile.get().toFile()); - tmpArt = convertImageToBytes(actualImage); - } - } catch (NullPointerException | IOException ignored) {} - } - artwork = tmpArt; - } - - /** - * Convert an Image into its' byte array representation. - * @param image Image to convert. - * @return image as byte[]. - */ - private static byte[] convertImageToBytes(Image image){ - int imageScaleToSize = 50; - try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){ - ImageIO.write(convertToBufferedImage(image.getScaledInstance(imageScaleToSize, imageScaleToSize, Image.SCALE_SMOOTH)), "jpg", baos); - baos.flush(); - return baos.toByteArray(); - } catch (IOException e) { return null; } - } - - /** - * Convert an Image to a BufferedImage. - * @param image Source image. - * @return image as BufferedImage. - */ - private static BufferedImage convertToBufferedImage(Image image) { - BufferedImage newImage = new BufferedImage( - image.getWidth(null), image.getHeight(null), - BufferedImage.TYPE_INT_ARGB); - Graphics2D g = newImage.createGraphics(); - g.drawImage(image, 0, 0, null); - g.dispose(); - return newImage; } @Override