package es.eucm.ead.importer.resources; import com.google.inject.Inject; import com.google.inject.Singleton; import es.eucm.ead.importer.OldReader; import es.eucm.ead.model.assets.AssetDescriptor; import es.eucm.ead.model.assets.drawable.EAdDrawable; import es.eucm.ead.model.assets.drawable.basics.Image; import es.eucm.ead.model.assets.drawable.basics.animation.Frame; import es.eucm.ead.model.assets.drawable.basics.animation.FramesAnimation; import es.eucm.ead.model.assets.multimedia.EAdSound; import es.eucm.ead.model.assets.multimedia.Music; import es.eucm.ead.model.assets.multimedia.Sound; import es.eucm.ead.model.assets.multimedia.Video; import es.eucm.eadventure.common.data.animation.Animation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; @Singleton public class ResourcesConverter { static private Logger logger = LoggerFactory .getLogger(ResourcesConverter.class); public static final String DRAWABLE = "drawable"; public static final String BINARY = "binary"; private String destinationPath; private OldReader oldReader; private Map<String, String> urisCorrespondences; private Map<String, Dimension> imageDimensions; /** * A map matching old uris with the new assets */ private Map<String, AssetDescriptor> assets; @Inject public ResourcesConverter(OldReader oldReader) { this.oldReader = oldReader; urisCorrespondences = new LinkedHashMap<String, String>(); assets = new LinkedHashMap<String, AssetDescriptor>(); imageDimensions = new HashMap<String, Dimension>(); } public void setPath(String destinationPath) { this.destinationPath = destinationPath; this.urisCorrespondences.clear(); createFolders(); } private void createFolders() { File f = new File(destinationPath + "/" + DRAWABLE); f.mkdirs(); f = new File(destinationPath + "/" + BINARY); f.mkdirs(); } /** * Returns a image in the new model with a path from the old model * * @param imagePath * @return */ public EAdDrawable getImage(String imagePath) { AssetDescriptor asset = assets.get(imagePath); if (asset == null) { String destinationImagePath = getPath(imagePath); asset = new Image(destinationImagePath); assets.put(imagePath, asset); } return (EAdDrawable) asset; } /** * Returns the sound associated to the soundPath in the old model * * @param soundPath * @return */ public EAdSound getSound(String soundPath) { AssetDescriptor asset = assets.get(soundPath); if (asset == null) { String destinationSoundPath = getPath(soundPath); asset = new Sound(destinationSoundPath); assets.put(soundPath, asset); } return (EAdSound) asset; } public Music getMusic(String musicPath) { AssetDescriptor asset = assets.get(musicPath); if (asset == null) { String destinationSoundPath = getPath(musicPath); asset = new Music(destinationSoundPath); assets.put(musicPath, asset); } return (Music) asset; } public Video getVideo(String videoPath) { AssetDescriptor asset = assets.get(videoPath); if (asset == null) { String destinationVideoPath = getPath(videoPath); asset = new Video(destinationVideoPath); assets.put(destinationVideoPath, asset); } return (Video) asset; } /** * Returns the path on the new model for a given path in the old model * * @param oldPath * @return */ public String getPath(String oldPath) { String newString = urisCorrespondences.get(oldPath); if (newString == null) { String folder = getFolder(oldPath); String fileName = oldPath.replace("/", "_"); newString = folder + "/" + fileName; if (!copyFile(oldPath, newString)) { logger.error("Missing resource: {}", oldPath); return null; } newString = "@" + newString; urisCorrespondences.put(oldPath, newString); } return newString; } private String getFolder(String oldString) { if (oldString.endsWith(".png") || oldString.endsWith(".jpg") || oldString.endsWith(".JPG") || oldString.endsWith(".PNG") || oldString.endsWith(".gif") || oldString.endsWith(".GIF")) return DRAWABLE; else return BINARY; } /** * Copy one file from old path to the new path * * @param oldPath * @param newPath * @return */ public boolean copyFile(String oldPath, String newPath) { logger.debug("-------- Copying from {} to {}", oldPath, newPath); File toResourceFile = new File(destinationPath, newPath); InputStream in = null; OutputStream out = null; boolean success = false; try { in = oldReader.getInputStream(oldPath); if (in != null) { out = new FileOutputStream(toResourceFile); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } success = true; } } catch (Exception e) { logger.error("Error copying '{}' to '{}'", oldPath, newPath); } finally { if (in != null) { try { in.close(); } catch (IOException e) { logger.error("Error accesing '{}'", oldPath); } } if (out != null) { try { out.close(); } catch (IOException e) { logger.error("Error accesing '{}'", newPath); } } } logger.debug("-------- Done."); return success; } public Animation getAnimation(String file) { return oldReader.getAnimation(file); } /** * Returns a frames animation for the given file * * @param assetPath it should end in *.eaa, *_01.png, *_01.jpg... * @return */ public EAdDrawable getFramesAnimation(String assetPath) { if (assetPath == null) return null; if (assets.containsKey(assetPath)) { return (EAdDrawable) assets.get(assetPath); } AssetDescriptor asset = null; // Special case if (assetPath.startsWith("assets/special/EmptyAnimation")) { if (assetPath.endsWith("_01.png")) { String uri = this.getPath(assetPath); return new Image(uri); } else if (!(assetPath.endsWith(".eaa") || assetPath .endsWith("_01.png"))) if (fileExists(assetPath + ".eaa")) assetPath += ".eaa"; else if (fileExists(assetPath + "_01.png")) { assetPath += "_01.png"; } else if (fileExists(assetPath + "_01.jpg")) { assetPath += "_01.jpg"; } else { logger.info("There was a problem with EmptyAnimation"); } } if (assetPath.startsWith("assets/animation") || assetPath.startsWith("assets/special/EmptyAnimation")) { if (assetPath.endsWith(".eaa") || (getFileExtension(assetPath) == null && fileExists(assetPath + ".eaa"))) { Animation a = oldReader.getAnimation(assetPath); // XXX animation transitions FramesAnimation frames = new FramesAnimation(); for (es.eucm.eadventure.common.data.animation.Frame f : a .getFrames()) { // XXX Frame sounds not imported long time = f.getTime(); String oldString = f.getUri(); String newString = getPath(oldString); Frame frame = new Frame(newString, (int) time); frames.addFrame(frame); asset = frames; } } else { asset = importImagesAnimation(assetPath); } } if (asset != null) assets.put(assetPath, asset); return (EAdDrawable) asset; } public boolean fileExists(String oldString) { boolean exists = false; InputStream is = oldReader.getInputStream(oldString); if (is != null) { exists = true; try { is.close(); } catch (IOException e) { } } return exists; } private String getFileExtension(String assetPath) { String prefix = "_01"; if (fileExists(assetPath + prefix + ".png")) { return ".png"; } else if (fileExists(assetPath + prefix + ".jpg")) { return ".jpg"; } else if (fileExists(assetPath + prefix + ".PNG")) { return ".PNG"; } else if (fileExists(assetPath + prefix + ".JPG")) { return ".JPG"; } else return null; } /** * Imports an animation in the form _01.png, _02.png, or _01.jpg, _02.jpg, * etc. * * @param assetPath the root asset path * @return the asset */ private AssetDescriptor importImagesAnimation(String assetPath) { String fileExtension = getFileExtension(assetPath); if (fileExtension == null) return null; FramesAnimation frames = new FramesAnimation(); int frame = 1; int frameTime = 500; String oldPath = assetPath + "_0" + frame++ + fileExtension; while (fileExists(oldPath)) { String newPath = getPath(oldPath); frames.addFrame(new Frame(newPath, frameTime)); oldPath = assetPath + "_0" + frame++ + fileExtension; } if (frames.getFrameCount() > 0) return frames; else return null; } public void clear() { assets.clear(); urisCorrespondences.clear(); } public Dimension getSize(String path) { logger.debug("-------- Size of {}", path); Dimension d = imageDimensions.get(path); if (d == null) { try { ImageInputStream in = ImageIO.createImageInputStream(oldReader .getInputStream(path)); try { final Iterator<ImageReader> readers = ImageIO .getImageReaders(in); if (readers.hasNext()) { ImageReader reader = readers.next(); try { reader.setInput(in); d = new Dimension(reader.getWidth(0), reader .getHeight(0)); } finally { reader.dispose(); } } } finally { if (in != null) in.close(); } logger.debug("-------- {}", d); } catch (Exception e) { logger.error("{}", e); d = new Dimension(1, 1); } } return d; } /** * Returns an image from the old model * * @param oldUri the uri for the image in the old model * @return the image loaded. You should flush the image when it's no longer needed */ public BufferedImage loadImage(String oldUri) { try { return ImageIO.read(oldReader.getInputStream(oldUri)); } catch (Exception e) { logger.error("Error loading {}", oldUri); } return null; } /** * Returns the project folder * * @return */ public String getProjectFolder() { return destinationPath; } }