rendered paste body/******************************************************************************* * Copyright 2011 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.badlogic.gdx.tools.skins;import java.awt.image.BufferedImage;import java.awt.image.WritableRaster;import java.io.File;import java.io.FilenameFilter;import java.io.Writer;import java.util.HashMap;import javax.imageio.ImageIO;import com.badlogic.gdx.files.FileHandle;import com.badlogic.gdx.graphics.Pixmap.Format;import com.badlogic.gdx.graphics.Texture.TextureFilter;import com.badlogic.gdx.graphics.Texture;import com.badlogic.gdx.graphics.g2d.BitmapFont;import com.badlogic.gdx.graphics.g2d.NinePatch;import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData;import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData;import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData.Region;import com.badlogic.gdx.graphics.g2d.TextureRegion;import com.badlogic.gdx.scenes.scene2d.ui.Skin;import com.badlogic.gdx.tools.FileProcessor;import com.badlogic.gdx.tools.imagepacker.TexturePacker;import com.badlogic.gdx.tools.imagepacker.TexturePacker.Settings;import com.badlogic.gdx.utils.Array;import com.badlogic.gdx.utils.GdxRuntimeException;import com.badlogic.gdx.utils.Json;import com.badlogic.gdx.utils.ObjectMap;import com.badlogic.gdx.utils.OrderedMap;/** * Utility to help build {@link Skin} files. * * Based on the original SkinPacker by Nathan Sweet * * @author tbone */public class NewSkinPacker{ /** * The directory containing all of the input resources. * * This includes TextureRegions (.png files) and NinePatch (.9.png files) */ public FileHandle inputDirectory; /** * The .json file to use as a template. * * The only *required* section is the 'styles' section which defines the * different resource mappings. */ public FileHandle inputSkinTemplate; /** * The output directory where the compiled skin file, font(s) and images * are put. Everything in this directory will be removed during pack. */ public FileHandle outputDirectory; /** * The texture atlas settings */ public Settings atlasSettings; /** * Constructs a new skin packer * * @param settings The {@link TexturePacker} {@link Settings} * @param inputDir Input directory containing the images. * @param outputDir Output directory * @param templateSkin Input template containing the style definitions */ public NewSkinPacker(Settings settings, FileHandle inputDir, FileHandle outputDir, FileHandle templateSkin) { atlasSettings = settings; inputDirectory = inputDir; outputDirectory = outputDir; inputSkinTemplate = templateSkin; } public NewSkinPacker() { atlasSettings = new Settings(); atlasSettings.alias = true; atlasSettings.pot = true; atlasSettings.maxWidth = 1024; atlasSettings.maxHeight = 1024; atlasSettings.defaultFilterMag = TextureFilter.Linear; atlasSettings.defaultFilterMin = TextureFilter.Linear; atlasSettings.duplicatePadding = false; } /** * Packs the skin with the current settings. */ public void pack() throws Exception { if (outputDirectory.exists()) outputDirectory.deleteDirectory(); outputDirectory.mkdirs(); final ObjectMap<String, int[]> nameToSplits = new ObjectMap<String, int[]>(); final TexturePacker packer = new TexturePacker(atlasSettings); // Region Processor FileProcessor regionProcessor = new FileProcessor() { protected void processFile(InputFile inputFile) throws Exception { packer.addImage(ImageIO.read(inputFile.inputFile), inputFile.outputFile.getName()); } }; regionProcessor.setInputFilter(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".png") && !name.endsWith(".9.png"); } }); regionProcessor.setRecursive(false); regionProcessor.setOutputSuffix(""); regionProcessor.process(inputDirectory.file(), outputDirectory.file()); // Nine Patch Processor FileProcessor ninePatchProcessor = new FileProcessor() { protected void processFile (InputFile inputFile) throws Exception { BufferedImage image = ImageIO.read(inputFile.inputFile); String name = inputFile.outputFile.getName(); name = name.substring(0, name.length() - 2); image = getSplits(image, name); packer.addImage(image, name); } private BufferedImage getSplits (BufferedImage image, String name) { WritableRaster raster = image.getRaster(); int[] rgba = new int[4]; int startX = 1; for (int x = 1; x < raster.getWidth() - 1; x++) { raster.getPixel(x, 0, rgba); if (rgba[3] == 0) continue; if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0) throw new RuntimeException("Unknown pixel:" + x + ",0: " + name); startX = x; break; } int endX; for (endX = startX; endX < raster.getWidth() - 1; endX++) { raster.getPixel(endX, 0, rgba); if (rgba[3] == 0) break; if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0) throw new RuntimeException("Unknown pixel " + endX + ",0: " + name); } for (int x = endX + 1; x < raster.getWidth() - 1; x++) { raster.getPixel(x, 0, rgba); if (rgba[3] != 0) throw new RuntimeException("Unknown pixel " + x + ",0: " + name); } int startY = 1; for (int y = 1; y < raster.getHeight() - 1; y++) { raster.getPixel(0, y, rgba); if (rgba[3] == 0) continue; if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0) throw new RuntimeException("Unknown pixel: 0," + y + ": " + name); startY = y; break; } int endY; for (endY = startY; endY < raster.getHeight() - 1; endY++) { raster.getPixel(0, endY, rgba); if (rgba[3] == 0) break; if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0) throw new RuntimeException("Unknown pixel 0," + endY + ": " + name); } for (int y = endY + 1; y < raster.getHeight() - 1; y++) { raster.getPixel(0, y, rgba); if (rgba[3] != 0) throw new RuntimeException("Unknown pixel 0," + y + ": " + name); } // No splits, or all splits. boolean singleRegion = startX == 1 && endX == 1 && startY == 1 && endY == 1; if (singleRegion) { endX = raster.getWidth(); endY = raster.getHeight(); } int[] splits = new int[5]; splits[0] = startX - 1; splits[1] = endX - 1; splits[2] = startY - 1; splits[3] = endY - 1; splits[4] = singleRegion ? 1 : 0; nameToSplits.put(name, splits); BufferedImage newImage = new BufferedImage(raster.getWidth() - 2, raster.getHeight() - 2, BufferedImage.TYPE_4BYTE_ABGR); newImage.getGraphics().drawImage(image, 0, 0, newImage.getWidth(), newImage.getHeight(), 1, 1, raster.getWidth() - 1, raster.getHeight() - 1, null); return newImage; } }; ninePatchProcessor.setRecursive(false); ninePatchProcessor.addInputSuffix(".9.png"); ninePatchProcessor.setOutputSuffix(""); ninePatchProcessor.process(inputDirectory.file(), outputDirectory.file()); // Pack the images final FileHandle packFile = outputDirectory.child("pack"); packer.process(outputDirectory.file(), packFile.file(), inputDirectory.name()); if (!packFile.exists()) throw new RuntimeException("No images were packed from input directory: " + inputDirectory.path()); // Builds a skin containing the new resources Skin skin = new Skin(); TextureAtlasData atlas = new TextureAtlasData(packFile, packFile.parent(), true); if (atlas.getPages().size > 1) throw new GdxRuntimeException("Skin images could not be packed on to a single image!"); atlas.getPages().get(0).textureFile.moveTo(outputDirectory.child(inputSkinTemplate.nameWithoutExtension() + ".png")); packFile.delete(); Texture texture = new Texture(1, 1, Format.Alpha); for (Region region : atlas.getRegions()) { int[] split = nameToSplits.get(region.name); TextureRegion textureRegion = new TextureRegion(texture, region.left, region.top, region.width, region.height); if (split == null) { skin.addResource(region.name, textureRegion); } else { if (split[4] == 1) skin.addResource(region.name, new NinePatch(textureRegion)); else skin.addResource(region.name, new NinePatch(textureRegion, split[0], region.width - split[1], split[2], region.height - split[3])); } } final FileHandle outputSkin = outputDirectory.child(inputSkinTemplate.name()); skin.save(outputSkin); // Build the new skin file Json json = new Json(); OrderedMap oldSkin = json.fromJson(OrderedMap.class, inputSkinTemplate); OrderedMap newSkin = json.fromJson(OrderedMap.class, outputSkin); OrderedMap oldResources = (OrderedMap)oldSkin.get("resources"); OrderedMap newResources = (OrderedMap)newSkin.get("resources"); OrderedMap newPatches = (OrderedMap)newResources.get(NinePatch.class.getName()); if (newPatches != null) { newPatches.orderedKeys().sort(); oldResources.put(NinePatch.class.getName(), newPatches); } OrderedMap newRegions = (OrderedMap)newResources.get(TextureRegion.class.getName()); if (newRegions != null) { newRegions.orderedKeys().sort(); oldResources.put(TextureRegion.class.getName(), newRegions); } Writer writer = outputSkin.writer(false); writer.write(json.prettyPrint(oldSkin, 130)); writer.flush(); writer.close(); // Copy the font file(s) OrderedMap fonts = (OrderedMap)oldResources.get(BitmapFont.class.getName()); for (String key : (Array<String>)fonts.orderedKeys()) { FileHandle fontFile = inputSkinTemplate.parent().child((String)((OrderedMap)fonts.get(key)).get("file")); FileHandle fontImage = new FileHandle(new BitmapFontData(fontFile, false).getImagePath()); fontFile.copyTo(outputDirectory); fontImage.copyTo(outputDirectory); } } public static void process(Settings settings, FileHandle inputDir, FileHandle outputDir, FileHandle inputSkinTemplate) throws Exception { new NewSkinPacker(settings, inputDir, outputDir, inputSkinTemplate).pack(); }}