com.uwsoft.editor.controlles.ResolutionManager.java Source code

Java tutorial

Introduction

Here is the source code for com.uwsoft.editor.controlles.ResolutionManager.java

Source

/*
 * ******************************************************************************
 *  * Copyright 2015 See AUTHORS file.
 *  *
 *  * 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 com.uwsoft.editor.controlles;

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.tools.texturepacker.TexturePacker;
import com.kotcrab.vis.ui.util.dialog.DialogUtils;
import com.mortennobel.imagescaling.ResampleOp;
import com.uwsoft.editor.data.manager.DataManager;
import com.uwsoft.editor.gdx.sandbox.Sandbox;
import com.uwsoft.editor.gdx.ui.ProgressHandler;
import com.uwsoft.editor.renderer.data.ProjectInfoVO;
import com.uwsoft.editor.renderer.data.ResolutionEntryVO;
import com.uwsoft.editor.tools.TextureUnpackerFixed;
import com.uwsoft.editor.utils.NinePatchUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ResolutionManager {
    private static final String EXTENSION_9PATCH = ".9.png";
    private final DataManager dataManager;
    public String curResolution;
    private float currentPercent = 0.0f;

    private ProgressHandler handler;

    public ResolutionManager(DataManager dataManager) {
        this.dataManager = dataManager;
    }

    public static BufferedImage imageResize(File file, float ratio) {
        BufferedImage destinationBufferedImage = null;
        try {
            BufferedImage sourceBufferedImage = ImageIO.read(file);
            if (ratio == 1.0) {
                return null;
            }
            // When image has to be resized smaller then 3 pixels we should leave it as is, as to ResampleOP limitations
            // But it should also trigger a warning dialog at the and of the import, to notify the user of non resized images.
            if (sourceBufferedImage.getWidth() * ratio < 3 || sourceBufferedImage.getHeight() * ratio < 3) {
                return null;
            }
            int newWidth = Math.max(3, Math.round(sourceBufferedImage.getWidth() * ratio));
            int newHeight = Math.max(3, Math.round(sourceBufferedImage.getHeight() * ratio));
            String name = file.getName();
            Integer[] patches = null;
            if (name.endsWith(EXTENSION_9PATCH)) {
                patches = NinePatchUtils.findPatches(sourceBufferedImage);
                sourceBufferedImage = NinePatchUtils.removePatches(sourceBufferedImage);

                newWidth = Math.round(sourceBufferedImage.getWidth() * ratio);
                newHeight = Math.round(sourceBufferedImage.getHeight() * ratio);
                System.out.println(sourceBufferedImage.getWidth());

                destinationBufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2 = destinationBufferedImage.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                        RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
                g2.drawImage(sourceBufferedImage, 0, 0, newWidth, newHeight, null);
                g2.dispose();

            } else {
                // resize with bilinear filter
                ResampleOp resampleOp = new ResampleOp(newWidth, newHeight);
                destinationBufferedImage = resampleOp.filter(sourceBufferedImage, null);
            }

            if (patches != null) {
                destinationBufferedImage = NinePatchUtils.convertTo9Patch(destinationBufferedImage, patches, ratio);
            }

        } catch (IOException ignored) {

        }

        return destinationBufferedImage;
    }

    public static float getResolutionRatio(ResolutionEntryVO resolution, ResolutionEntryVO originalResolution) {
        float a;
        float b;
        switch (resolution.base) {
        default:
        case 0:
            a = resolution.width;
            b = originalResolution.width;
            break;
        case 1:
            a = resolution.height;
            b = originalResolution.height;
            break;
        }
        return a / b;
    }

    public void createNewResolution(String name, int width, int height, final String resolutionBase,
            final ProgressHandler handler) {
        this.handler = handler;
        final ResolutionEntryVO newResolution = new ResolutionEntryVO();
        newResolution.name = name;
        newResolution.width = width;
        newResolution.height = height;
        newResolution.base = resolutionBase.equals("width") ? 0 : 1;
        dataManager.getCurrentProjectInfoVO().resolutions.add(newResolution);
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(new Runnable() {
            @Override
            public void run() {
                // create new folder structure
                String projPath = dataManager.getCurrentWorkingPath() + "/"
                        + dataManager.getCurrentProjectVO().projectName;
                String sourcePath = projPath + "/" + "assets/orig/images";
                String targetPath = projPath + "/" + "assets/" + newResolution.name + "/images";
                createIfNotExist(sourcePath);
                createIfNotExist(projPath + "/" + "assets/" + newResolution.name + "/pack");
                copyTexturesFromTo(sourcePath, targetPath);
                int resizeWarnings = resizeTextures(targetPath, newResolution);
                rePackProjectImages(newResolution);
                createResizedAnimations(newResolution);
                changePercentBy(5);
                DialogUtils.showOKDialog(Sandbox.getInstance().getUIStage(), "Warning", resizeWarnings
                        + " images were not resized for smaller resolutions due to already small size ( < 3px )");
            }
        });
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                DataManager.getInstance().saveCurrentProject();
                handler.progressComplete();
            }
        });
        executor.shutdown();
    }

    //    private static BufferedImage convertTo9Patch(BufferedImage image) {

    //    }

    private void changePercentBy(float value) {
        currentPercent += value;
        handler.progressChanged(currentPercent);
    }

    public void createResizedAnimations(ResolutionEntryVO resolution) {
        String currProjectPath = dataManager.getCurrentWorkingPath() + File.separator
                + dataManager.getCurrentProjectVO().projectName;

        // Unpack spine orig
        File spineSourceDir = new File(currProjectPath + File.separator + "assets/orig/spine-animations");
        if (spineSourceDir.exists()) {
            for (File entry : spineSourceDir.listFiles()) {
                if (entry.isDirectory()) {
                    String animName = FilenameUtils.removeExtension(entry.getName());
                    createResizedSpineAnimation(animName, resolution);
                }
            }
        }

        //Unpack sprite orig
        File spriteSourceDir = new File(currProjectPath + File.separator + "assets/orig/sprite-animations");
        if (spriteSourceDir.exists()) {
            for (File entry : spriteSourceDir.listFiles()) {
                if (entry.isDirectory()) {
                    String animName = FilenameUtils.removeExtension(entry.getName());
                    createResizedSpriteAnimation(animName, resolution);
                }
            }
        }
    }

    public void createResizedSpriteAnimation(String animName, ResolutionEntryVO resolution) {
        String currProjectPath = dataManager.getCurrentWorkingPath() + File.separator
                + dataManager.getCurrentProjectVO().projectName;
        File animAtlasFile = new File(currProjectPath + File.separator + "assets/orig/sprite-animations/" + animName
                + "/" + animName + ".atlas");

        String tmpPath = currProjectPath + File.separator + "assets/orig/sprite-animations/" + animName + "/tmp";
        File tmpFolder = new File(tmpPath);
        try {
            FileUtils.forceMkdir(new File(
                    currProjectPath + File.separator + "assets/" + resolution.name + "/sprite-animations/"));
            FileUtils.forceMkdir(new File(currProjectPath + File.separator + "assets/" + resolution.name
                    + "/spine-animations/" + animName));

            String targetPath = currProjectPath + File.separator + "assets/" + resolution.name
                    + "/sprite-animations/" + animName;
            File targetFolder = new File(targetPath);

            unpackAtlasIntoTmpFolder(animAtlasFile, tmpPath);
            resizeImagesTmpDirToResolution(animName, tmpFolder, resolution, targetFolder);

            FileUtils.deleteDirectory(tmpFolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void unpackAtlasIntoTmpFolder(File atlasFile, String tmpDir) {
        FileHandle atlasFileHandle = new FileHandle(atlasFile);
        TextureAtlas.TextureAtlasData atlasData = new TextureAtlas.TextureAtlasData(atlasFileHandle,
                atlasFileHandle.parent(), false);
        TextureUnpackerFixed unpacker = new TextureUnpackerFixed();
        unpacker.splitAtlas(atlasData, tmpDir);
    }

    public void createResizedSpineAnimation(String animName, ResolutionEntryVO resolution) {
        String currProjectPath = dataManager.getCurrentWorkingPath() + File.separator
                + dataManager.getCurrentProjectVO().projectName;

        File animAtlasFile = new File(currProjectPath + File.separator + "assets/orig/spine-animations/" + animName
                + "/" + animName + ".atlas");

        String tmpPath = currProjectPath + File.separator + "assets/orig/spine-animations/" + animName + "/tmp";
        File tmpFolder = new File(tmpPath);
        try {
            FileUtils.forceMkdir(new File(
                    currProjectPath + File.separator + "assets/" + resolution.name + "/spine-animations/"));
            FileUtils.forceMkdir(new File(currProjectPath + File.separator + "assets/" + resolution.name
                    + "/spine-animations/" + animName));

            String targetPath = currProjectPath + File.separator + "assets/" + resolution.name
                    + "/spine-animations/" + animName;
            File targetFolder = new File(targetPath);

            unpackAtlasIntoTmpFolder(animAtlasFile, tmpPath);
            resizeImagesTmpDirToResolution(animName, tmpFolder, resolution, targetFolder);

            FileUtils.deleteDirectory(tmpFolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void resizeSpriteAnimationForAllResolutions(String animName, ProjectInfoVO currentProjectInfoVO) {
        String currProjectPath = dataManager.getCurrentWorkingPath() + File.separator
                + dataManager.getCurrentProjectVO().projectName;

        File atlasFile = new File(
                currProjectPath + File.separator + "assets" + File.separator + "orig" + File.separator
                        + "sprite-animations" + File.separator + animName + File.separator + animName + ".atlas");

        String tmpDir = currProjectPath + File.separator + "assets" + File.separator + "orig" + File.separator
                + "sprite-animations" + File.separator + animName + File.separator + "tmp";
        File sourceFolder = new File(tmpDir);

        unpackAtlasIntoTmpFolder(atlasFile, tmpDir);
        try {
            for (ResolutionEntryVO resolutionEntryVO : currentProjectInfoVO.resolutions) {
                String spriteAnimationsRoot = currProjectPath + File.separator + "assets" + File.separator
                        + resolutionEntryVO.name + File.separator + "sprite-animations";
                FileUtils.forceMkdir(new File(spriteAnimationsRoot));
                String targetPath = spriteAnimationsRoot + File.separator + animName;
                File targetFolder = new File(targetPath);

                resizeImagesTmpDirToResolution(animName, sourceFolder, resolutionEntryVO, targetFolder);
            }

            FileUtils.deleteDirectory(sourceFolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void resizeSpineAnimationForAllResolutions(File atlasFile, ProjectInfoVO currentProjectInfoVO) {

        String fileNameWithOutExt = FilenameUtils.removeExtension(atlasFile.getName());
        String tmpDir = dataManager.getCurrentWorkingPath() + File.separator
                + dataManager.getCurrentProjectVO().projectName + "/assets/orig/spine-animations" + File.separator
                + fileNameWithOutExt + File.separator + "tmp";
        File sourceFolder = new File(tmpDir);

        unpackAtlasIntoTmpFolder(atlasFile, tmpDir);
        try {
            for (ResolutionEntryVO resolutionEntryVO : currentProjectInfoVO.resolutions) {
                FileUtils.forceMkdir(new File(dataManager.getCurrentWorkingPath() + "/"
                        + dataManager.getCurrentProjectVO().projectName + File.separator + "assets" + File.separator
                        + resolutionEntryVO.name + File.separator + "spine-animations"));
                String targetPath = dataManager.getCurrentWorkingPath() + "/"
                        + dataManager.getCurrentProjectVO().projectName + File.separator + "assets" + File.separator
                        + resolutionEntryVO.name + File.separator + "spine-animations" + File.separator
                        + fileNameWithOutExt;
                FileUtils.forceMkdir(new File(targetPath));
                File targetFolder = new File(targetPath);
                resizeImagesTmpDirToResolution(atlasFile.getName(), sourceFolder, resolutionEntryVO, targetFolder);
            }
            FileUtils.deleteDirectory(sourceFolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void rePackProjectImages(ResolutionEntryVO resEntry) {
        TexturePacker.Settings settings = new TexturePacker.Settings();

        settings.flattenPaths = true;
        //        settings.maxHeight = getMinSquareNum(resEntry.height);
        //        settings.maxWidth = getMinSquareNum(resEntry.height);
        settings.maxHeight = Integer.parseInt(dataManager.getCurrentProjectVO().texturepackerHeight);
        settings.maxWidth = Integer.parseInt(dataManager.getCurrentProjectVO().texturepackerWidth);
        settings.filterMag = Texture.TextureFilter.Linear;
        settings.filterMin = Texture.TextureFilter.Linear;

        TexturePacker tp = new TexturePacker(settings);

        String sourcePath = dataManager.getCurrentWorkingPath() + "/"
                + dataManager.getCurrentProjectVO().projectName + "/assets/" + resEntry.name + "/images";
        String outputPath = dataManager.getCurrentWorkingPath() + "/"
                + dataManager.getCurrentProjectVO().projectName + "/assets/" + resEntry.name + "/pack";

        FileHandle sourceDir = new FileHandle(sourcePath);
        File outputDir = new File(outputPath);

        try {
            FileUtils.forceMkdir(outputDir);
            FileUtils.cleanDirectory(outputDir);
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (FileHandle entry : sourceDir.list()) {
            String filename = entry.file().getName();
            String extension = filename.substring(filename.lastIndexOf(".") + 1, filename.length()).toLowerCase();
            if (extension.equals("png")) {
                tp.addImage(entry.file());
            }
        }

        tp.pack(outputDir, "pack");
    }

    private int resizeTextures(String path, ResolutionEntryVO resolution) {
        float ratio = getResolutionRatio(resolution, dataManager.getCurrentProjectInfoVO().originalResolution);
        FileHandle targetDir = new FileHandle(path);
        FileHandle[] entries = targetDir.list(new DataManager.PngFilenameFilter());
        float perResizePercent = 95.0f / entries.length;

        int resizeWarnings = 0;

        for (FileHandle entry : entries) {
            try {
                File file = entry.file();
                File destinationFile = new File(path + "/" + file.getName());
                BufferedImage resizedImage = ResolutionManager.imageResize(file, ratio);
                if (resizedImage == null) {
                    resizeWarnings++;
                    ImageIO.write(ImageIO.read(file), "png", destinationFile);
                } else {
                    ImageIO.write(ResolutionManager.imageResize(file, ratio), "png", destinationFile);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            changePercentBy(perResizePercent);
        }

        return resizeWarnings;
    }

    private void copyTexturesFromTo(String fromPath, String toPath) {
        FileHandle sourceDir = new FileHandle(fromPath);
        FileHandle[] entries = sourceDir.list(new DataManager.PngFilenameFilter());
        float perCopyPercent = 10.0f / entries.length;
        for (FileHandle entry : entries) {
            File file = entry.file();
            String filename = file.getName();
            File target = new File(toPath + "/" + filename);
            try {
                FileUtils.copyFile(file, target);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        changePercentBy(perCopyPercent);
    }

    private File createIfNotExist(String dirPath) {
        File theDir = new File(dirPath);
        boolean result = false;
        // if the directory does not exist, create it
        if (!theDir.exists()) {
            result = theDir.mkdir();
        }

        if (result)
            return theDir;
        else
            return null;
    }

    public void resizeImagesTmpDirToResolution(String packName, File sourceFolder, ResolutionEntryVO resolution,
            File targetFolder) {
        float ratio = ResolutionManager.getResolutionRatio(resolution,
                dataManager.getCurrentProjectInfoVO().originalResolution);

        if (targetFolder.exists()) {
            try {
                FileUtils.cleanDirectory(targetFolder);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // now pack
        TexturePacker.Settings settings = new TexturePacker.Settings();

        settings.flattenPaths = true;
        settings.maxHeight = getMinSquareNum(resolution.height);
        settings.maxWidth = getMinSquareNum(resolution.height);
        settings.filterMag = Texture.TextureFilter.Linear;
        settings.filterMin = Texture.TextureFilter.Linear;

        TexturePacker tp = new TexturePacker(settings);
        for (final File fileEntry : sourceFolder.listFiles()) {
            if (!fileEntry.isDirectory()) {
                BufferedImage bufferedImage = ResolutionManager.imageResize(fileEntry, ratio);
                tp.addImage(bufferedImage, FilenameUtils.removeExtension(fileEntry.getName()));
            }
        }

        tp.pack(targetFolder, packName);
    }

    public static int getMinSquareNum(int num) {

        // if (num < 1024) return 1024;

        // if (num < 2048) return 2048;

        // if (num < 4096) return 4096;

        return 4096;
    }

    public float getCurrentMul() {
        ResolutionEntryVO curRes = dataManager.getCurrentProjectInfoVO().getResolution(curResolution);
        float mul = 1f;
        if (!curResolution.equals("orig")) {
            if (curRes.base == 0) {
                mul = (float) curRes.width / (float) dataManager.getCurrentProjectInfoVO().originalResolution.width;
            } else {
                mul = (float) curRes.height
                        / (float) dataManager.getCurrentProjectInfoVO().originalResolution.height;
            }
        }

        return mul;
    }

    public void rePackProjectImagesForAllResolutions() {
        rePackProjectImages(dataManager.getCurrentProjectInfoVO().originalResolution);
        for (ResolutionEntryVO resolutionEntryVO : dataManager.getCurrentProjectInfoVO().resolutions) {
            rePackProjectImages(resolutionEntryVO);
        }
    }

    public void deleteResolution(int index) {
        ResolutionEntryVO resolutionEntryVO = dataManager.getCurrentProjectInfoVO().resolutions.remove(index);
        try {
            FileUtils.deleteDirectory(new File(dataManager.getWorkspacePath() + "/"
                    + dataManager.currentProjectVO.projectName + "/assets/" + resolutionEntryVO.name));
        } catch (IOException ignored) {
            ignored.printStackTrace();
        }
        dataManager.saveCurrentProject();
        dataManager.openProjectAndLoadAllData(dataManager.currentProjectVO.projectName, "orig");
    }
}