游戏开发中,图片资源的精简

蒙板压缩对比图:(此方法可大幅减小游戏包的大小)



包大小对比:



在游戏开发中,包的大小总是与图片资源的大小密切相关,而图片资源中,大多为带有透明度信息的png图像。

那么,如何精简png图片资源呢?


1、图像压缩是一种方法,然而随着压缩率的增大、图片品质也越来越差。(舍弃)

2、我们另辟蹊径,采用png图像拆分。(近乎无损,资源精简)


一、原理:将png图像转化为两张jpeg图像进行存储


pngSplit下载

pngSplit使用说明


二、使用方法

1、LibGdx中,通过Pixmap使用

	
// 如工程目录assets/texture/0_1.jpeg下:
/** 从工程资源路径下获取图像,如:filePath1 = "texture/0_1.jpeg"、filePath2 = "texture/0_2.jpeg" */
public static Texture getTexture(String filePath1, String filePath2)
{
	try
	{
		Pixmap pic1 = new Pixmap(Gdx.files.internal(filePath1));
		Pixmap pic2 = new Pixmap(Gdx.files.internal(filePath2));
		
		Pixmap pic = Combine(pic1, pic2);	// 合并为png图像
		return new Texture(pic);			// 创建Texture
	}
	catch (Exception ex)
	{
		return null;
	}
}

/** 从Pic和Mask合成图像 */
public static Pixmap Combine(Pixmap Pic, Pixmap Mask)
{
	int width = Pic.getWidth(), height = Pic.getHeight();	// 获取图像的尺寸
	
	Pixmap image = new Pixmap(closestTwoPower(width), closestTwoPower(height), Format.RGBA8888);	// 合成尺寸为2的幂
	
	int color1, color2, color, alpha;
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height; j++)
		{
			color1 = Pic.getPixel(i, j);	// 原图像像素信息
			color2 = Mask.getPixel(i, j);	// 原图像透明度信息
			
			alpha = (color2 & 0xff00) >> 8;							// 透明度
			color = alpha == 0 ? 0 : (color1 & 0xffffff00) | alpha;	// 合成像素点
			
			image.drawPixel(i, j, color);	// 生成图像
		}
	}
	return image;
}

/** 获取最接近于n的2的幂 */
public static int closestTwoPower(int n)
{
	int power = 1;
	while (power < n)
		power <<= 1;
	return power;
}



2、安卓中,通过 Bitmap使用(未调试)

	
/** 从工程资源路径下获取图像,如:filePath1 = "0_1.jpeg"、filePath2 = "0_2.jpeg" */
public static Bitmap getBitmap(String pathName1, String pathName2)
{
	try
	{
		Bitmap pic1 = BitmapFactory.decodeFile(pathName1);
		Bitmap pic2 = BitmapFactory.decodeFile(pathName2);
		
		Bitmap pic = Combine(pic1, pic2);	// 合并为png图像
		return pic;
	}
	catch (Exception ex)
	{
		return null;
	}
}
	
/** 从Pic和Mask创建bitmap图像 */
public static Bitmap Combine(Bitmap Pic, Bitmap Mask)
{
	int width = Pic.getWidth(), height = Pic.getHeight(); // 获取图像的尺寸
	Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
	
	int color1, color2, color;
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height; j++)
		{
			color1 = Pic.getPixel(i, j); // 原图像像素信息
			color2 = Pic.getPixel(i, j); // 原图像透明度信息
			color = (color1 & 0x00ffffff) | ((color2 & 0x00ff0000) << 8); // 合成像素点
			
			image.setPixel(i, j, color); // 生成图像
		}
	}
	return image;
}


附类文件:(测试通过)

Bitmap2.java

/** 2015-5-25上午10:10:15 wangzhongyuan */

package com.hlge.lib.base;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;

import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Environment;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.hlge.lib.HlgeActivity;
import com.hlge.lib.tool.Tools;


/** Bitmap2,对Bitmap进行相关图像处理、转化Bitmap的尺寸为2的幂,推荐使用函数getPixmapExt获取图像资源 ----- 2015-5-21 下午2:06:43 wangzhongyuan */
public class Bitmap2
{
	/** 临时记录载入图像的尺寸 */
	static int sizex, sizey;
	
	/** 标识是否保存至缓存文件 */
	private static boolean SaveTmpFile = false;
	
	/** 图片缓存文件拓展名 */
	private static String tmpExt = ".png";				// 缓存文件的实际类型
	public static final String ReadSaveExt = ".png";	// 缓存文件读取和写入使用的文件拓展名
	
	// -------------------------------------------------------------------------------------------------
	
	/** 此hansh表中的图像资源,直接从内部资源进行载入 */
	public static HashMap<String, String> LoadList = new HashMap<String, String>(); // 以 path + name为索引,拓展名为值
	
	/** 此hansh表中的图像资源,从内部资源进行蒙板合成 */
	public static ArrayList<String> CombineList = new ArrayList<String>();			// 以 path + name为键值
	
	/** 对path路径下的所有图像按文件名分类, path = "texture/" */
	public static void groupPicByName(String path)
	{
		// 路径有效性判定
		FileHandle dir = Gdx.files.internal(path);
		if (!dir.exists() || !dir.isDirectory())
			Tools.Log(path + "不是有效路径!");
		else
		{
			FileHandle[] files = dir.list();
			for (FileHandle file : files)
			{
				String name = file.name();
				if (name.endsWith("_1.jpeg") || name.endsWith("_2.jpeg"))
				{
					name = name.substring(0, name.lastIndexOf("_"));
					if (!CombineList.contains(path + name)) CombineList.add(path + name);						// 蒙板合并图像
				}
				else if (name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg"))
				{
					name = name.substring(0, name.lastIndexOf("."));
					if (!LoadList.containsKey(path + name)) LoadList.put(path + name, "." + file.extension());	// 直接载入图像
				}
			}
		}
	}
	
	/** 预加载图像,载入进度 */
	public static int loadprocess = 0;
	
	/** 预加载所有蒙板图像,合成外部png缓存文件,在游戏载入时调用该函数,提前处理图像资源*/
	public static void loadResources()
	{
		// 将文件夹中的图像资源按文件名分类存入LoadList和CombineList
		groupPicByName("texture/");
		groupPicByName("spine/");
		
		// // 判定是否已对所有图像资源进行了缓存载入
		// String value = LocalDB.readData("Bitmap2_loadResources");
		// if (value.equals("3")) return;
		// LocalDB.saveData("Bitmap2_loadResources", "3");
		
		for (int i = 0; i < CombineList.size(); i++)
		{
			String pathName = CombineList.get(i);
			
			FileHandle file = new FileHandle(getPath() + pathName + ReadSaveExt);	// 缓存文件判定
			if (!file.exists())
			{
				Bitmap pic = getBitmap(pathName + "_1.jpeg", pathName + "_2.jpeg");	// 合成图像
				
				int end = pathName.lastIndexOf("/") + 1;
				String path = end != -1 ? pathName.substring(0, end) : "";
				String name = end != -1 ? pathName.substring(end) : pathName;
				
				Bitmap2.save(path, name, pic);	// 保存至文件缓存
				pic.recycle();					// 释放资源
			}
			
			loadprocess = (int) ((((float) i) / CombineList.size()) * 100);
			Tools.Log("蒙板图像载入进度 " + loadprocess + "% ");
		}
		loadprocess = 100;
	}
	
	/** 从目录assets/texture/下获取图像 pic.*,对应参数为:path = "texture/", fileName = "pic" */
	public static Pixmap getPixmapExt(String path, String fileName)
	{
		Pixmap pic = null;
		
		try
		{
			pic = Pixmap2.read(path, fileName, ReadSaveExt);	// 从缓存中读取
			if (pic != null) return pic;
			
			String pathName = path + fileName;
			if (CombineList.contains(pathName))
			// 直接从蒙板合成图像
			{
				Bitmap tmp = getBitmap(pathName + "_1.jpeg", pathName + "_2.jpeg");
				pic = ToPixmap(tmp);
				Bitmap2.save(path, fileName, tmp);				// 保存至文件缓存
				tmp.recycle();									// 释放资源
			}
			else if (LoadList.containsKey(pathName))
			// 直接从内部资源载入图像
			{
				String Ext = LoadList.get(pathName);
				pic = new Pixmap(Gdx.files.internal(pathName + Ext));
				
				// 载入图像尺寸校验,需为2的次幂
				int width = pic.getWidth(), height = pic.getHeight();
				int w = Bitmap2.closestTwoPower(width), h = Bitmap2.closestTwoPower(height);
				if (w != width || h != height)
				{
					Bitmap tmp = getBitmap(pathName + Ext);
					pic = ToPixmap(tmp);
					Bitmap2.save(path, fileName, tmp);				// 保存至文件缓存
					tmp.recycle();									// 释放资源
				}
			}
			else
			// 检索所有拓展名载入
			{
				Bitmap tmp = getBitmapExtProcess(path, fileName);	// 从工程内部资源文件生成
				Bitmap2.save(path, fileName, tmp); 					// 保存至文件缓存
				pic = ToPixmap(tmp);								// 转化为Pixmap
				tmp.recycle();
			}
			return pic;
		}
		catch (Exception ex)
		{
			Tools.Log("载入图像" + path + fileName + "出错!");
			return null;
		}
	}
	
	/** 从目录assets/texture/下获取图像 pic.*,对应参数为:path = "texture/", fileName = "pic",获取图像后自动缓存至文件 */
	public static Bitmap getBitmapExt(String path, String fileName)
	{
		Bitmap pic = Bitmap2.read(path, fileName);		// 优先从本地文件缓存中读取
		if (pic != null)
			return pic;
		else
		{
			pic = getBitmapExtProcess(path, fileName);	// 从工程内部资源文件生成
			Bitmap2.save(path, fileName, pic); 			// 保存至文件缓存
			return pic;
		}
	}
	
	/** 从目录assets/texture/下获取图像 pic.*,对应参数为:path = "texture/", fileName = "pic" */
	private static Bitmap getBitmapExtProcess(String path, String fileName)
	{
		String filePath = path + fileName;	// 工程内部资源路径+文件名(无拓展名)
		Bitmap pic;
		
		// 载入png或jpg图像
		String[] Exts = { ".png", ".jpg", ".jpeg" };
		for (String exts : Exts)
		{
			tmpExt = exts;
			pic = getAssetsBitmap(path + fileName + exts);
			if (pic != null) return FormatSize(pic);
		}
		
		// 从pngSplit工具,导出的蒙板图像载入
		tmpExt = ".png";
		pic = getBitmap(path + fileName + "_1.jpeg", path + fileName + "_2.jpeg");
		if (pic != null) return pic;
		
		Tools.Log(filePath + " Bitmap载入出错!");
		return null;
	}
	
	// pic = getImageFromAssetsFile("assets/texture/0.png");
	
	/** 从Assets目录中读取图片, fileName = "texture/0_1.jpeg" */
	@SuppressWarnings("unused")
	public static Bitmap getAssetsBitmap(String fileName)
	{
		// 判断文件是否存在
		FileHandle handle = Gdx.files.internal(fileName);
		if (!handle.exists()) return null;
		
		Bitmap image = null;
		AssetManager manager = HlgeActivity.$this.getResources().getAssets();
		try
		{
			InputStream is = manager.open(fileName);
			image = BitmapFactory.decodeStream(is);
			is.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		return image;
	}
	
	// 如工程目录assets/texture/0_1.jpeg下:
	/** 获取工程目录下的图像,如:filePath = "texture/0_1.jpeg" */
	public static Bitmap getBitmap(String filePath)
	{
		Bitmap pic = getAssetsBitmap(filePath);	// 从assets获取图像
		pic = FormatSize(pic);					// 转化为2的n次幂
		return pic;
	}
	
	// 如工程目录assets/texture/0_1.jpeg下:
	/** 从pngSplit工具,导出的两张蒙板图像创建,如:filePath1 = "texture/0_1.jpeg"、filePath2 = "texture/0_2.jpeg" */
	public static Bitmap getBitmap(String filePath1, String filePath2)
	{
		try
		{
			Bitmap pic1 = getAssetsBitmap(filePath1);
			Bitmap pic2 = getAssetsBitmap(filePath2);
			
			Bitmap pic = Bitmap2.Combine(pic1, pic2);
			
			pic1.recycle();
			pic2.recycle();
			return pic;
		}
		catch (Exception ex)
		{
			Tools.Log("从蒙板资源创建Bitmap出错!(" + filePath1 + "、" + filePath2 + ")");
			return null;
		}
	}
	
	/** 从两张蒙板图像Pic和Mask,合成图像 */
	public static Bitmap Combine(Bitmap Pic, Bitmap Mask)
	{
		try
		{
			int width = Pic.getWidth(), height = Pic.getHeight();	// 获取图像的尺寸
			Bitmap2.sizex = width;									// 记录图像原尺寸
			Bitmap2.sizey = height;
			
			int w = Bitmap2.closestTwoPower(width), h = Bitmap2.closestTwoPower(height);
			Bitmap image = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); // 合成尺寸为2的幂
			
			// image.eraseColor(0xffffffff);
			
			int color1, color2, color;
			for (int i = 0; i < width; i++)
			{
				for (int j = 0; j < height; j++)
				{
					color1 = Pic.getPixel(i, j); 	// 原图像像素信息
					color2 = Mask.getPixel(i, j); 	// 原图像透明度信息
					color = (color1 & 0x00ffffff) | ((color2 & 0x00ff0000) << 8); // 合成像素点
					
					image.setPixel(i, j, color); 	// 生成图像
				}
			}
			SaveTmpFile = true;		// 可保存当前图像至缓存
			return image;
		}
		catch (Exception ex)
		{
			Tools.Log("从蒙板合成图像出错!");
			return null;
		}
	}
	
	/** 将Pic转化为尺寸为2的幂的图像 */
	public static Bitmap FormatSize(Bitmap Pic)
	{
		try
		{
			int width = Pic.getWidth(), height = Pic.getHeight();	// 获取图像的尺寸
			Bitmap2.sizex = width;									// 记录图像原尺寸
			Bitmap2.sizey = height;
			
			int w = Bitmap2.closestTwoPower(width), h = Bitmap2.closestTwoPower(height);
			if (w == width && h == height) return Pic; 				// 若原图像尺寸为2的幂,则直接返回原图像
				
			// 构建2的n次幂图像
			Bitmap image = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
			
			Canvas g2d = new Canvas(image);
			g2d.drawBitmap(Pic, 0, 0, new Paint());
			
			// Paint p = new Paint();
			// p.setColor(Color.WHITE);
			// p.setAntiAlias(true);
			// p.setFilterBitmap(true);
			
			// int color;
			// for (int i = 0; i < width; i++)
			// {
			// for (int j = 0; j < height; j++)
			// {
			// color = Pic.getPixel(i, j); // 原图像像素信息
			// image.setPixel(i, j, color); // 生成图像
			// }
			// }
			
			SaveTmpFile = true;	// 可保存当前图像至缓存
			return image;
		}
		catch (Exception ex)
		{
			Tools.Log("Bitmap尺寸转化为2的幂出错!");
			return null;
		}
		
	}
	
	/** 获取最接近于n的2的幂 */
	public static int closestTwoPower(int n)
	{
		int power = 1;
		while (power < n)
			power <<= 1;
		return power;
	}
	
	/** 获取SD卡或内部存储路径,优先选择SD卡 , "/tmp/" */
	public static String getPath()
	{
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
			return Environment.getExternalStorageDirectory().getPath() + "/tmp/";
		else
			return "/tmp/";
	}
	
	/** 从本地缓存文件载入Pixmap, subPath为子文件夹,如:"sub/" */
	public static Bitmap read(String subPath, String fileName)
	{
		try
		{
			// 从指定路径获取文件
			String path = getPath() + subPath, name = fileName + ReadSaveExt;
			File file = new File(path, name);
			
			// 创建Bitmap
			if (file.exists())
				return BitmapFactory.decodeFile(path + name);
			else
				return null;
		}
		catch (Exception e)
		{
			Tools.Log("Bitmap文件读取出错(" + fileName + tmpExt + ") " + e.toString());
			return null;
		}
	}
	
	// /** 保存pixmap到缓存文件fileName, subPath为子文件夹,如:"sub/", 不进行条件判断存储 */
	// public static void saveOne(String subPath, String fileName, Bitmap bitmap)
	// {
	// if (bitmap == null) return;
	//
	// SaveTmpFile = true;
	// save(subPath, fileName, bitmap);
	//
	// bitmap = null;
	// }
	
	/** 保存pixmap到缓存文件fileName, subPath为子文件夹,如:"sub/" */
	public static void save(String subPath, String fileName, Bitmap bitmap)
	{
		if (bitmap == null) return;	// 图像为null
			
		if (SaveTmpFile)
			SaveTmpFile = false;	// 可保存当前图像至缓存
		else
			return;
		
		try
		{
			// 确保路径文件存在
			String path = getPath() + subPath, name = fileName + ReadSaveExt;
			File dir = new File(path);
			if (!dir.exists()) dir.mkdirs();
			
			File file = new File(path, name);
			if (!file.exists()) file.delete();
			file.createNewFile();
			
			// 压缩格式设置
			CompressFormat format = CompressFormat.PNG;
			if (tmpExt.equalsIgnoreCase(".jpg") || tmpExt.equalsIgnoreCase(".jpeg")) format = CompressFormat.JPEG;
			
			// 保存图像到文件
			Bitmap2.save(bitmap, file, format);
		}
		catch (Exception e)
		{
			Tools.Log("Bitmap写入文件出错(" + fileName + ") " + e.toString());
		}
	}
	
	/** 保存bitmap到file中,按格式format进行压缩 */
	public static void save(Bitmap bitmap, File file, CompressFormat format) // CompressFormat.PNG
	{
		try
		{
			// 将bitmap,压缩到字节输出流
			ByteArrayOutputStream stream = new ByteArrayOutputStream();
			bitmap.compress(format, format == CompressFormat.JPEG ? 100 : 1, stream); // jpg图像最高质量存储,png图像最低质量存储
			
			// 从文件输出流,写入文件
			FileOutputStream fout = new FileOutputStream(file);
			fout.write(stream.toByteArray());
			fout.flush();
			fout.close();
		}
		catch (Exception e)
		{
			Tools.Log("保存bitmap到file中出错" + e.toString());
		}
	}
	
	/** Bitmap向Pixmap的转化 */
	public static Pixmap ToPixmap(Bitmap bitmap)
	{
		if (bitmap == null) return null;
		
		// 从Bitmap创建输出流
		int size = bitmap.getWidth() * bitmap.getHeight();
		ByteArrayOutputStream outStream = new ByteArrayOutputStream(size);
		bitmap.compress(Bitmap.CompressFormat.PNG, 0, outStream);
		
		// 从输出流创建Pixmap
		byte[] img = outStream.toByteArray();
		return new Pixmap(img, 0, img.length);
	}
}

Pixmap2.java

package com.hlge.lib.base;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;

import android.graphics.Bitmap;
import android.os.Environment;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.PixmapIO;
import com.hlge.lib.tool.LocalDB;
import com.hlge.lib.tool.Tools;


/** Pixmap2,对Pixmap进行相关图像处理、转化Pixmap的尺寸为2的幂, 内部功能实现基于Bitmap2 ----- 2015-5-21 下午2:06:43 wangzhongyuan */
public class Pixmap2
{
	/** 临时记录载入图像的尺寸 */
	static int sizex, sizey;
	
	/** 临时记录用于存储的Bitmap */
	static Bitmap tmpSaveBitmap = null;
	
	// -------------------------------------------------------------------------------------------------
	
	/** 载入路径下path所有图像资源, path = "texture/" */
	public static void loadPixmapAll(String path)
	{
		// 判定是否已对所有图像资源进行了缓存载入
		String value = LocalDB.readData("loadPixmapAll");
		if (value.equals("2")) return;
		LocalDB.saveData("loadPixmapAll", "2");
		
		// FileHandle handle = new FileHandle(getPath() + path);
		// if(handle.exists()) return;
		
		// 获取路径下所有文件
		FileHandle dir = Gdx.files.internal(path);
		if (!dir.exists() || !dir.isDirectory()) return;
		
		// 提取文件名
		ArrayList<String> pathNames = new ArrayList<String>();
		FileHandle[] files = dir.list();
		
		String tmp;		// 获取文件名,不含路径
		for (FileHandle file : files)
		{
			tmp = path.equals("") ? file.path() : file.path().substring(path.length());
			pathNames.add(tmp);
		}
		
		try
		{
			String name, name2;
			while (pathNames.size() > 0)
			{
				name = pathNames.remove(0);
				
				boolean b_1 = name.endsWith("_1.jpeg"), b_2 = name.endsWith("_2.jpeg");
				if (b_1 || b_2)	// 为蒙板导出的图像 "_1.jpeg", "_2.jpeg"合并为一个文件
				{
					name2 = b_1 ? name.replace("_1.jpeg", "_2.jpeg") : name.replace("_2.jpeg", "_1.jpeg");
					if (pathNames.contains(name2))
					{
						pathNames.remove(name2);
						name = name.substring(0, name.lastIndexOf("_"));
					}
					else
						name = name.substring(0, name.lastIndexOf("."));
				}
				else if (name.contains(".")) name = name.substring(0, name.lastIndexOf("."));
				
				Pixmap pic = getPixmapExt(path, name);	// 从工程资源目录下载入所有资源,生成资源缓存文件
				pic.dispose();							// 释放纹理
				
				Tools.Log("缓存文件" + path + name + " 剩余未载入个数:" + pathNames.size());
			}
		}
		catch (Exception ex)
		{
			Tools.Log("载入路径" + path + "下的图像出错,剩余未载入个数:" + pathNames.size());
		}
	}
	
	/** 从目录assets/texture/下获取图像 pic.*,对应参数为:path = "texture/", fileName = "pic" */
	public static Pixmap getPixmapExt(String path, String fileName, String tmpExt)
	{
		String tmp = Pixmap2.tmpExt;
		Pixmap2.tmpExt = tmpExt;
		
		Pixmap pic = getPixmapExt(path, fileName);
		
		Pixmap2.tmpExt = tmp;
		return pic;
	}
	
	/** 从目录assets/texture/下获取图像 pic.*,对应参数为:path = "texture/", fileName = "pic",获取图像后自动缓存至文件 */
	public static Pixmap getPixmapExt(String path, String fileName)
	{
		// Pixmap pic = Pixmap2.read(path, fileName); // 优先从本地文件缓存中读取
		Pixmap pic = Pixmap2.read(path, fileName, Bitmap2.ReadSaveExt);		// 优先从本地文件缓存中读取
		if (pic != null)
			return pic;
		else
		{
			pic = getPixmapExtProcess(path, fileName);	// 工程内部资源文件生成
			// Pixmap2.save(path, fileName, pic); // 保存至文件缓存
			
			Bitmap2.save(path, fileName, tmpSaveBitmap);// 保存至文件缓存
			resetSize(pic);
			
			tmpSaveBitmap.recycle();	// 释放资源
			tmpSaveBitmap = null;
			
			return pic;
		}
	}
	
	/** 从目录assets/texture/下获取图像 pic.*,对应参数为:path = "texture/", fileName = "pic" */
	private static Pixmap getPixmapExtProcess(String path, String fileName)
	{
		String filePath = path + fileName;	// 工程内部资源路径+文件名(无拓展名)
		FileHandle handle, handle2;
		
		// 从png图像载入
		handle = Gdx.files.internal(filePath + ".png");
		if (handle.exists()) return getPixmap(handle);
		
		// 从jpg图像载入
		handle = Gdx.files.internal(filePath + ".jpg");
		if (handle.exists()) return getPixmap(handle);
		
		handle = Gdx.files.internal(filePath + ".jpeg");
		if (handle.exists()) return getPixmap(handle);
		
		// 从pngSplit工具,导出的蒙板图像载入
		handle = Gdx.files.internal(filePath + "_1.jpeg");
		handle2 = Gdx.files.internal(filePath + "_2.jpeg");
		// if (handle.exists() && handle2.exists()) return Combine(getPixmap(handle), getPixmap(handle2));
		if (handle.exists() && handle2.exists()) return getPixmap(filePath + "_1.jpeg", filePath + "_2.jpeg");
		
		Tools.Log(filePath + "Pixmap载入出错!");
		return null;
	}
	
	/** 设置当前pic的尺寸信息 */
	private static void resetSize(Pixmap pic)
	{
		if (Bitmap2.sizex == 0 || Bitmap2.sizey == 0)
		{
			if (pic == null)
				sizex = sizey = 0;
			else
			{
				sizex = pic.getWidth();
				sizey = pic.getHeight();
			}
		}
		else
		{
			sizex = Bitmap2.sizex;
			sizey = Bitmap2.sizey;
		}
	}
	
	/** 获取工程路径下的图像为Pixmap,如:filePath = "texture/0.png" */
	public static Pixmap getPixmap(String filePath)
	{
		FileHandle handle = Gdx.files.internal(filePath);
		if (handle.exists())			// 从给定的路径载入
		{
			// 从缓存读取
			String path = handle.parent().path() + "/", name = handle.nameWithoutExtension();
			Pixmap pic = Pixmap2.read(path, name, Bitmap2.ReadSaveExt);
			
			// 从文件载入
			if (pic == null) pic = getPixmap(handle);
			Bitmap2.save(path, name, tmpSaveBitmap);// 保存至文件缓存
			resetSize(pic);
			
			tmpSaveBitmap.recycle();	// 释放资源
			tmpSaveBitmap = null;
			
			return pic;
		}
		else if (filePath.contains("."))// 给定路径文件不存在,尝试其他后缀名载入
		{
			// 剔除后缀名
			int index = filePath.lastIndexOf(".");
			String name = filePath.substring(0, index);
			
			// 分割子路径和文件名
			index = filePath.lastIndexOf("/");
			if (index == -1)
				filePath = "";
			else
			{
				filePath = name.substring(0, index + 1);	// 子路径
				name = name.substring(index + 1);			// 文件名
			}
			return getPixmapExt(filePath, name);
		}
		else
			Tools.Log("从( " + filePath + " )创建Pixmap出错!");
		return null;
	}
	
	/** 获取handle对应的Pixmap,并转化其尺寸为2的幂 */
	public static Pixmap getPixmap(FileHandle handle)
	{
		try
		{
			// Pixmap pic = new Pixmap(handle); // 获取对应的图像
			// pic = Pixmap2.FormatSize(pic); // 图像尺寸转化为2的幂
			
			Bitmap tmp = Bitmap2.getBitmap(handle.path());	// 从Bitmap载入图像
			tmpSaveBitmap = tmp;							// 记录该Bitmap,待存储
			Pixmap pic = Bitmap2.ToPixmap(tmp);				// 转化为Pixmap
			
			return pic;
		}
		catch (Exception ex)
		{
			Tools.Log("从FileHandle=" + handle.toString() + "创建Pixmap出错!");
			return null;
		}
	}
	
	// 如工程目录assets/texture/0_1.jpeg下:
	/** 从pngSplit工具,导出的两张蒙板图像创建,如:filePath1 = "texture/0_1.jpeg"、filePath2 = "texture/0_2.jpeg" */
	public static Pixmap getPixmap(String filePath1, String filePath2)
	{
		try
		{
			// 从Pixmap载入像素有差异(舍弃)
			// Pixmap pic1 = new Pixmap(Gdx.files.internal(filePath1));
			// Pixmap pic2 = new Pixmap(Gdx.files.internal(filePath2));
			// return Pixmap2.Combine(pic1, pic2);
			
			// 以Bitmap方式载入,合成为Pixmap
			// Bitmap pic1 = Bitmap2.getAssetsBitmap(filePath1);
			// Bitmap pic2 = Bitmap2.getAssetsBitmap(filePath2);
			//
			// return Pixmap2.Combine(pic1, pic2);
			
			// 以Bitmap方式载入,转化为Pixmap
			Bitmap pic = Bitmap2.getBitmap(filePath1, filePath2);
			tmpSaveBitmap = pic;		// 记录该Bitmap,待存储
			return Bitmap2.ToPixmap(pic);
		}
		catch (Exception ex)
		{
			Tools.Log("从蒙板资源创建Pixmap出错!(" + filePath1 + "、" + filePath2 + ")");
			return null;
		}
	}
	
	/** 从两张蒙板图像Pic和Mask,合成图像 —— 从Pixmap载入图像,获取的像素值与工具导出像素有差异 */
	public static Pixmap Combine(Pixmap Pic, Pixmap Mask)
	{
		// Log.i("Format", Pic.getFormat().name() + " " + Mask.getFormat().name());
		// Format f1 = Pic.getFormat(), f2 = Mask.getFormat();
		
		try
		{
			int width = Pic.getWidth(), height = Pic.getHeight();	// 获取图像的尺寸
			Pixmap2.sizex = width;									// 记录图像原尺寸
			Pixmap2.sizey = height;
			
			Pixmap image = new Pixmap(Pixmap2.closestTwoPower(width), Pixmap2.closestTwoPower(height), Format.RGBA8888);	// 合成尺寸为2的幂
			
			int color1, color2, color, alpha = 0;
			for (int i = 0; i < width; i++)
			{
				for (int j = 0; j < height; j++)
				{
					color1 = Pic.getPixel(i, j);	// 原图像像素信息
					color2 = Mask.getPixel(i, j);	// 原图像透明度信息
					
					color1 &= 0xffffff00;			// 获取RGB0
					alpha = ((color2 & 0x0000ff00) >>> 8);		// 获取A
					color = alpha == 0 ? 0 : (color1 | alpha);	// 合成RGBA
					
					image.drawPixel(i, j, color);	// 生成图像
				}
			}
			
			return image;
		}
		catch (Exception ex)
		{
			Tools.Log("从蒙板合成图像出错!");
			return null;
		}
	}
	
	/** 从两张Bitmap蒙板图像Pic和Mask,合成Pixmap */
	public static Pixmap Combine(Bitmap Pic, Bitmap Mask)
	{
		try
		{
			int width = Pic.getWidth(), height = Pic.getHeight();	// 获取图像的尺寸
			Pixmap2.sizex = width;									// 记录图像原尺寸
			Pixmap2.sizey = height;
			
			int w = Pixmap2.closestTwoPower(width), h = Pixmap2.closestTwoPower(height);
			Pixmap image = new Pixmap(w, h, Format.RGBA8888);		// 合成尺寸为2的幂
			
			int color1, color2, color;
			for (int i = 0; i < width; i++)
			{
				for (int j = 0; j < height; j++)
				{
					color1 = Pic.getPixel(i, j); 	// 原图像像素信息, ARGB_8888
					color2 = Mask.getPixel(i, j); 	// 原图像透明度信息, ARGB_8888
					color = (color1 << 8) | (color2 & 0x000000ff); // 合成像素点, RGBA8888
					
					image.drawPixel(i, j, color); // 生成图像
				}
			}
			return image;
		}
		catch (Exception ex)
		{
			Tools.Log("从蒙板合成图像出错!");
			return null;
		}
	}
	
	/** 从两张蒙板图像Pic和Mask,合成图像 */
	public static Pixmap CombineT(Pixmap Pic, Pixmap Mask)
	{
		// Log.i("Format", Pic.getFormat().name() + " " + Mask.getFormat().name());
		// Format f1 = Pic.getFormat(), f2 = Mask.getFormat();
		
		StringBuffer str1 = new StringBuffer(), str2 = new StringBuffer(), str3 = new StringBuffer();
		
		try
		{
			int width = Pic.getWidth(), height = Pic.getHeight();	// 获取图像的尺寸
			Pixmap2.sizex = width;									// 记录图像原尺寸
			Pixmap2.sizey = height;
			
			Pixmap image = new Pixmap(Pixmap2.closestTwoPower(width), Pixmap2.closestTwoPower(height), Format.RGBA8888);	// 合成尺寸为2的幂
			
			int color1, color2, color, alpha = 0;
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					color1 = Pic.getPixel(j, i);	// 原图像像素信息
					color2 = Mask.getPixel(j, i);	// 原图像透明度信息
					
					str1.append(Integer.toHexString(color1) + (j < width - 1 ? "," : ""));
					str2.append(Integer.toHexString(color2) + (j < width - 1 ? "," : ""));
					
					color1 &= 0xffffff00;						// 获取RGB0
					alpha = ((color2 & 0x0000ff00) >>> 8);		// 获取A
					color = alpha == 0 ? 0 : (color1 | alpha);	// 合成RGBA
					
					str3.append(Integer.toHexString(color) + (j < width - 1 ? "," : ""));
					
					image.drawPixel(j, i, color);	// 生成图像
				}
				str1.append(i < height - 1 ? "\r\n" : "");
				str2.append(i < height - 1 ? "\r\n" : "");
				str3.append(i < height - 1 ? "\r\n" : "");
			}
			
			FileHandle handle = Gdx.files.internal(getPath() + "color.txt");
			
			if (!handle.exists()) handle.file().createNewFile();
			
			FileOutputStream fout = new FileOutputStream(new File(getPath(), "color.txt"));
			PrintStream ps = new PrintStream(fout);
			
			ps.println("\r\n\r\n\r\n" + str1.toString());
			ps.append("\r\n\r\n\r\n" + str2.toString());
			ps.append("\r\n\r\n\r\n" + str3.toString());
			
			ps.close();
			
			return image;
		}
		catch (Exception ex)
		{
			Tools.Log("从蒙板合成图像出错!");
			return null;
		}
	}
	
	/** 将Pic转化为尺寸为2的幂的图像 */
	public static Pixmap FormatSize(Pixmap Pic)
	{
		// Log.i("Format", Pic.getFormat().name());
		
		try
		{
			int width = Pic.getWidth(), height = Pic.getHeight();	// 获取图像的尺寸
			Pixmap2.sizex = width;									// 记录图像原尺寸
			Pixmap2.sizey = height;
			
			Pixmap image = new Pixmap(Pixmap2.closestTwoPower(width), Pixmap2.closestTwoPower(height), Pic.getFormat());
			if (image.getWidth() == width && image.getHeight() == height) return Pic; // 若原图像尺寸为2的幂,则直接返回原图像
				
			image.drawPixmap(Pic, 0, 0);
			// int color;
			// for (int i = 0; i < width; i++)
			// {
			// for (int j = 0; j < height; j++)
			// {
			// color = Pic.getPixel(i, j); // 原图像像素信息
			// image.drawPixel(i, j, color); // 生成图像
			// }
			// }
			return image;
		}
		catch (Exception ex)
		{
			Tools.Log("Pixmap尺寸转化为2的幂出错!");
			return null;
		}
		
	}
	
	/** 获取最接近于n的2的幂 */
	public static int closestTwoPower(int n)
	{
		int power = 1;
		while (power < n)
			power <<= 1;
		return power;
	}
	
	/** 获取SD卡或内部存储路径,优先选择SD卡 , "/tmp/" */
	public static String getPath()
	{
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
			return Environment.getExternalStorageDirectory().getPath() + "/tmp/";
		else
			return "/tmp/";
	}
	
	/** 图片缓存文件拓展名 */
	private static String tmpExt = ".byte";
	
	/** 保存pixmap到缓存文件fileName, subPath为子文件夹,如:"sub/" */
	public static void save(String subPath, String fileName, Pixmap pixmap)
	{
		try
		{
			pixmap.setColor(0);
			FileHandle file = new FileHandle(getPath() + subPath + fileName + tmpExt);
			if (file.exists()) file.delete();		// 若文件已存在,则删除
			if (tmpExt.equals(".byte"))
				PixmapIO.writeCIM(file, pixmap);
			else
				PixmapIO.writePNG(file, pixmap);	// 将pixmap写入文件中缓存
		}
		catch (Exception e)
		{
			Tools.Log("Pixmap写入文件出错(" + fileName + ") " + e.toString());
		}
	}
	
	/** 从本地缓存文件载入Pixmap, subPath为子文件夹,如:"sub/" */
	public static Pixmap read(String subPath, String fileName)
	{
		return read(subPath, fileName, tmpExt);
	}
	
	/** 从本地缓存文件载入Pixmap,拓展名为tmpExt, subPath为子文件夹,如:"sub/" */
	public static Pixmap read(String subPath, String fileName, String tmpExt)
	{
		try
		{
			FileHandle file = new FileHandle(getPath() + subPath + fileName + tmpExt);
			if (tmpExt.equals(".byte"))
				return !file.exists() ? null : PixmapIO.readCIM(file);
			else
				return !file.exists() ? null : new Pixmap(file);
		}
		catch (Exception e)
		{
			Tools.Log("Pixmap文件读取出错(" + fileName + tmpExt + ") " + e.toString());
			return null;
		}
	}
}


Tools.java

package com.hlge.lib.tool;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Random;

import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.ScreenUtils;
import com.hlge.lib.HlgeActivity;
import com.hlge.lib.HlgeConfig;
import com.hlge.lib.HlgeHelper;
import com.hlge.lib.HlgeLauncher;


/** Tools 工具类,封装一些常用功能函数 ----- 2015-5-16 下午3:55:16 wangzhongyuan */
public class Tools
{
	// ------------------------------------------------功能函数-----------------------------------------------
	
	/** 控制手机震动 */
	public static void shakePhone(short milliseconds)
	{
		Gdx.input.vibrate(milliseconds);
	}
	
	/** 打开url地址页 */
	public static void loadUrl(String url)
	{
		Intent it = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
		HlgeActivity.$this.startActivity(it);
	}
	
	/** 将字符串转化为数值,默认值为0 */
	public static int parseInt(String strNum)
	{
		int num = 0;
		try
		{
			num = Integer.parseInt(strNum.trim());
		}
		catch (Exception ex)
		{}
		;
		return num;
	}
	
	/** 将字符串转化为数值,默认值为0 */
	public static float parseFloat(String strNum)
	{
		float num = 0;
		try
		{
			num = Float.parseFloat(strNum.trim());
		}
		catch (Exception ex)
		{}
		;
		return num;
	}
	
	// --------------------------------------------------随机数、序列数生成、数组排序------------------------------------------------
	
	// 随机数发生器
	public static final Random random = new Random();
	
	/** 生成[0, n)范围的随机整数 */
	public static int random(int n)
	{
		return random.nextInt(n);
	}
	
	/** 生成[lower, upper]范围的随机整数 */
	public static int random(int lower, int upper)
	{
		if (lower > upper)
			return random(upper, lower);
		else
			return random.nextInt(upper - lower + 1) + lower;
	}
	
	/** 序列数生成算法,生成1到n的随机序列数组,每个数值出现且仅出现一次 */
	public static int[] getSerial(int n)
	{
		Random Rnd = new Random();
		
		int[] tmp = new int[n];
		int[] num1 = new int[n];
		for (int i0 = 1; i0 <= n; i0++)
			num1[i0 - 1] = i0;
		
		for (int i = num1.length; i > 0; i--)
		{
			Rnd.setSeed(Rnd.nextLong());
			int index = Rnd.nextInt(i);
			
			// 随机选中一个数
			tmp[i - 1] = num1[index];
			
			// 剔除选中的数值
			int[] num2 = new int[i - 1];
			for (int j = 0; j < i; j++)
				if (j < index)
					num2[j] = num1[j];
				else if (j > index) num2[j - 1] = num1[j];
			num1 = num2;
		}
		
		return tmp;
	}
	
	/** 数组排序函数 */
	public static int[] sort(int[] data)
	{
		int tmp;
		for (int i = 0; i < data.length - 1; i++)
		{
			for (int j = i + 1; j < data.length; j++)
				if (data[i] > data[j])
				{
					tmp = data[i];
					data[i] = data[j];
					data[j] = tmp;
				}
		}
		return data.clone();
	}
	
	// ------------------------------------------------区域颜色填充-----------------------------------------------
	
	/** 用颜色color填充整个界面,Rect为坐标为左下坐标系 */
	public static void filledRect(Color color)
	{
		filledRect(HlgeLauncher.batch, HlgeLauncher.render, color, null);
	}
	
	/** 在Rect区域用颜色color进行填充,Rect为坐标为左下坐标系 */
	public static void filledRect(Color color, Rectangle Rect)
	{
		filledRect(HlgeLauncher.batch, HlgeLauncher.render, color, Rect);
	}
	
	/** 在Rect区域用颜色color进行填充,Rect为坐标为左下坐标系 */
	public static void filledRect(SpriteBatch batch, Color color, Rectangle Rect)
	{
		filledRect(batch, HlgeLauncher.render, color, Rect);
	}
	
	/** 在Rect区域用颜色color进行填充,Rect为坐标为左下坐标系 */
	public static void filledRect(SpriteBatch batch, ShapeRenderer render, Color color, Rectangle Rect)
	{
		if (Rect == null) Rect = new Rectangle(0, 0, HlgeConfig.CONF_SCREEN_WIDTH, HlgeConfig.CONF_SCREEN_HEIGHT);
		
		batch.end();
		
		Gdx.gl.glEnable(GL20.GL_BLEND);
		Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
		
		render.begin(ShapeRenderer.ShapeType.FilledRectangle);
		render.setColor(color);
		render.filledRect(Rect.x / HlgeHelper.scalex, Rect.y / HlgeHelper.scaley, Rect.width / HlgeHelper.scalex, Rect.height / HlgeHelper.scaley);
		render.end();
		
		batch.begin();
	}
	
	// ------------------------------------------------半透阴影的绘制-----------------------------------------------
	/** 绘制半透阴影,不透明度alpha */
	public static void drawShadow(float alpha)
	{
		// drawShadow(0, 0, HlgeConfig.CONF_SCREEN_WIDTH, HlgeConfig.CONF_SCREEN_HEIGHT, 0, 0, 0, 0, alpha, 1);
		filledRect(new Color(0, 0, 0, alpha));
	}
	
	/** 绘制半透阴影, 区域(x,y,w,h)高亮,不透明度alpha */
	public static void drawShadow(float x, float y, float w, float h, float alpha)
	{
		drawShadow(0, 0, HlgeConfig.CONF_SCREEN_WIDTH, HlgeConfig.CONF_SCREEN_HEIGHT, x, y, x + w, y + h, alpha, 20);
	}
	
	// 绘制半透阴影,在区域(x1,y1)-(x2,y2)中,除区域范围(x3,y3)-(x4,y4)外绘制阴影,阴影不透明度为alpha,分fade次进行渲染
	private static void drawShadow(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float alpha, int fade)
	{
		HlgeLauncher.batch.end();
		
		Gdx.gl.glEnable(GL20.GL_BLEND);
		Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
		
		HlgeLauncher.render.begin(ShapeRenderer.ShapeType.FilledRectangle);
		
		if (fade < 1) fade = 1;
		
		alpha = alpha / fade;
		HlgeLauncher.render.setColor(0, 0, 0, alpha);
		
		if (x4 == x3 || y4 == y3)
			drawShadow(HlgeLauncher.render, x1, y1, x2, y2, x3, y3, x4, y4);
		else
		{
			float boder = 15f / fade;
			
			fade += 10;
			while (fade-- > 10)
			{
				x3 += boder;
				y3 += boder;
				x4 -= boder;
				y4 -= boder;
				drawShadow(HlgeLauncher.render, x1, y1, x2, y2, x3, y3, x4, y4);
			}
		}
		
		HlgeLauncher.render.end();
		HlgeLauncher.batch.begin();
	}
	
	// 绘制半透阴影,在区域(x1,y1)-(x2,y2)中,除区域范围(x3,y3)-(x4,y4)外绘制阴影
	private static void drawShadow(ShapeRenderer renderer, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
	{
		// 转化为badlogic.gdx坐标系
		y3 = HlgeConfig.CONF_SCREEN_HEIGHT - y3;
		y4 = HlgeConfig.CONF_SCREEN_HEIGHT - y4;
		y1 = HlgeConfig.CONF_SCREEN_HEIGHT - y1;
		y2 = HlgeConfig.CONF_SCREEN_HEIGHT - y2;
		
		// 屏幕尺寸缩放,位置变换
		x1 /= HlgeHelper.scalex;
		y1 /= HlgeHelper.scaley;
		x2 /= HlgeHelper.scalex;
		y2 /= HlgeHelper.scaley;
		x3 /= HlgeHelper.scalex;
		y3 /= HlgeHelper.scaley;
		x4 /= HlgeHelper.scalex;
		y4 /= HlgeHelper.scaley;
		
		if (x4 == x3 || y4 == y3)
			renderer.filledRect(x1, y2, x2 - x1, y1 - y2);
		else
		{
			renderer.filledRect(x1, y2, x2 - x1, y4 - y2);
			renderer.filledRect(x1, y4, x3 - x1, y3 - y4);
			renderer.filledRect(x4, y4, x2 - x4, y3 - y4);
			renderer.filledRect(x1, y3, x2 - x1, y1 - y3);
		}
	}
	
	// --------------------------------------------------文件数据读取,保存------------------------------------------------
	
	/** 从输入流读取数据 */
	public static String ReadString(DataInputStream dis)
	{
		try
		{
			ArrayList<Byte> stringByte = new ArrayList<Byte>();
			
			while (true)
			{
				byte data;
				data = dis.readByte();
				if (data != 0)
					stringByte.add(data);
				else
					break;
			}
			
			byte datas[] = new byte[stringByte.size()];
			for (int i = 0; i < datas.length; i++)
				datas[i] = stringByte.get(i);
			
			return new String(datas, "GBK");
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		return null;
	}
	
	/** 从字节数组的offset处开始读取len个字节,形成一个int返回 */
	public static final int readFromByteArray(byte[] data, int offset, int length)
	{
		int param = 0;
		int mbit = 0;
		for (int i = length - 1; i >= 0; i--)
		{
			mbit = (length - i - 1) << 3;
			param |= ((data[offset + i] << mbit) & (0xff << mbit));
		}
		
		switch (length)
		{
			case 1:
				param = (byte) param;
				break;
			case 2:
				param = (short) param;
				break;
			case 4:
				param = (int) param;
				break;
		}
		
		return param;
	}
	
	/** 读取乐堂工具导出资源file,读取类型mode */
	public static String getTextFile(String file, byte mode)
	{
		InputStream is = read(file, mode).read();
		byte[] buffer;
		try
		{
			buffer = new byte[is.available()];
			is.read(buffer);
			return new String(buffer);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		return "";
	}
	
	/** 文件类型 */
	public static final byte FILE_TYPE_ACTOR = 1, FILE_TYPE_RAW = 2, FILE_TYPE_MAP = 3, FILE_TYPE_SCENE = 4, FILE_TYPE_XML = 5, FILE_TYPE_FONT = 6,
			FILE_TYPE_PIC = 7, FILE_TYPE_SOUND = 8, FILE_TYPE_CG = 9, FILE_TYPE_QUESTVAR = 10, FILE_TYPE_SCRIPT = 11, FILE_TYPE_ABSOLUTE = 12;
	
	/** 乐堂工具导出资源的路径读取 */
	public static FileHandle read(String filename, byte mode)
	{
		switch (mode)
		{
			case FILE_TYPE_ACTOR:
				FileHandle fh = Gdx.files.internal("actor/" + filename);
				return fh.exists() ? fh : Gdx.files.internal("actor/" + LangManager.lang() + "/" + filename);
				
			case FILE_TYPE_QUESTVAR:
				return Gdx.files.internal("scene/" + filename);
				
			case FILE_TYPE_MAP:
				return Gdx.files.internal("map/" + filename);
				
			case FILE_TYPE_RAW:
				return Gdx.files.internal("raw/" + filename);
				
			case FILE_TYPE_SCENE:
				return Gdx.files.internal("scene/" + filename);
				
			case FILE_TYPE_XML:
				return Gdx.files.internal("xml/" + filename);
				
			case FILE_TYPE_FONT:
				return Gdx.files.internal("font/" + filename);
				
			case FILE_TYPE_PIC:
				return Gdx.files.internal("texture/" + filename);
				
			case FILE_TYPE_SOUND:
				return Gdx.files.internal("snd/" + filename);
				
			case FILE_TYPE_CG:
				return Gdx.files.internal("cg/" + filename);
				
			case FILE_TYPE_SCRIPT:
				return Gdx.files.internal("scene/sd/" + filename);
				
			case FILE_TYPE_ABSOLUTE:
				return new FileHandle(new File(filename));
				
			default:
				throw new RuntimeException("文件类型有误,位置read()");
		}
	}
	
	/** 获取当前屏幕截图 */
	public static Bitmap captureScreen(int x, int y, int w, int h, boolean flipy)
	{
		byte[] arr = ScreenUtils.getFrameBufferPixels(x, y, w, h, flipy);
		int[] bitArr = new int[w * h];
		for (int i = 0; i < arr.length; i += 4)
		{
			bitArr[i / 4] = (int) (((arr[i + 3] & 0xFF) << 24) | ((arr[i] & 0xFF) << 16) | ((arr[i + 1] & 0xFF) << 8) | (arr[i + 2] & 0xFF));
		}
		return Bitmap.createBitmap(bitArr, w, h, Bitmap.Config.ARGB_8888);
	}
	
	/** 保存图片filename到路径savePath */
	public static void saveImage(Bitmap bitmap, String savePath, String filename)
	{
		if (getSDCardPath() != null) savePath += getSDCardPath();
		
		try
		{
			File path = new File(savePath);
			
			String filePath = savePath + "/" + filename;
			File file = new File(filePath);
			
			if (!path.exists()) path.mkdirs();
			if (!file.exists()) file.createNewFile();
			
			FileOutputStream fos = null;
			fos = new FileOutputStream(file);
			
			if (null != fos)
			{
				if (filename.endsWith(".png"))
					bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
				else
				{
					Log.e("Utils.saveImage()", "filename must be end with .png!!!");
					fos.close();
				}
				
				fos.flush();
				fos.close();
				Log.v("tag", filename + "save to" + savePath + "successful!");
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/** 获取SDCard的路径 */
	private static String getSDCardPath()
	{
		File sdcardDir = null;
		
		boolean sdcardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
		if (sdcardExist) sdcardDir = Environment.getExternalStorageDirectory(); // 判断SDCard是否存在
			
		return sdcardDir.toString();
	}
	
	/** 获取SD卡或内部存储路径,优先选择SD卡 , "/tmp/" */
	public static String getTmpPath()
	{
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
			return Environment.getExternalStorageDirectory().getPath() + "/tmp/";
		else
			return "/tmp/";
	}
	
	/** 将数据data保存至文件file中, Dir = "texture/", fileName = "color.txt" */
	public static void WriteStringToFile(String data)
	{
		WriteStringToFile(data, getTmpPath(), "tmp.txt");
	}
	
	/** 将数据data保存至文件file中, Dir = "texture/", fileName = "color.txt" */
	public static void WriteStringToFile(String data, String Dir, String fileName)
	{
		try
		{
			// 确保文件路径 Dir + fileName 存在,不存在则创建
			File dir = new File(Dir);
			if (!dir.exists()) dir.mkdirs();
			
			File file = new File((Dir.endsWith("/") ? Dir : Dir + "/") + fileName);
			if (!file.exists()) file.createNewFile();
			
			// 将字符串data写入文件
			FileOutputStream fout = new FileOutputStream(file);
			PrintStream ps = new PrintStream(fout);
			ps.println(data);
			ps.close();
		}
		catch (Exception e)
		{
			Tools.Log("字符串写入文件出错!");
		}
	}
	
	// --------------------------------------------------坐标变换、点、矩形碰撞检测------------------------------------------------
	
	/** 坐标系变换:左上、左下坐标系,y坐标变换 */
	public static float coordinateTrans(float y, float height)
	{
		return HlgeConfig.CONF_SCREEN_HEIGHT - y - height;
	}
	
	/** 二维坐标转化为一维坐标 */
	public static int point2indexInArray(int i, int j, int columns)
	{
		i = i * columns + j;
		return i < 0 ? 0 : i;
	}
	
	/** 点与矩形碰状,判断点(x,y)是否在矩形区域内 */
	public static boolean isPointInRect(float x, float y, Rectangle Rect)
	{
		if (Rect == null) return false;
		return Tools.isPointInRect(x, y, Rect.x, Rect.y, Rect.x + Rect.width, Rect.y + Rect.height);
	}
	
	/** 点与矩形碰状,判断点(x,y)是否在矩形区域内 */
	public static boolean isPointInRect(float x, float y, float x1, float y1, float x2, float y2)
	{
		if (x2 > x1)
		{
			if (x > x2 || x < x1) return false;
		}
		else
		{
			if (x < x2 || x > x1) return false;
		}
		
		if (y2 > y1)
		{
			if (y > y2 || y < y1) return false;
		}
		else
		{
			if (y < y2 || y > y1) return false;
		}
		
		return true;
	}
	
	/** 判断点(x,y)是否在矩形rect 范围内 */
	public static boolean isPointInRect(int X, int Y, short[] rect)
	{
		int w = rect[2];
		int h = rect[3];
		
		if ((w | h) < 0) return false;
		
		int x = rect[0];
		int y = rect[1];
		if (X < x || Y < y) return false;
		
		w += x;
		h += y;
		
		return ((w < x || w > X) && (h < y || h > Y));
	}
	
	/** 2个矩形是否相交 */
	public static boolean isRectIntersect(int[] rect0, int[] rect1)
	{
		if (rect0 == null || rect1 == null) return false;
		return !(rect0[0] > rect1[2] || rect1[0] > rect0[2] || rect0[1] > rect1[3] || rect1[1] > rect0[3]);
	}
	
	/** 2个矩形是否相交 */
	public static boolean isRectIntersect(short[] rect0, short[] rect1)
	{
		if (rect0 == null || rect1 == null) return false;
		return !(rect0[0] > rect1[2] || rect1[0] > rect0[2] || rect0[1] > rect1[3] || rect1[1] > rect0[3]);
	}
	
	/** 左下原点坐标系中,获取坐标(x, y)逆时针针旋转degree角度后的坐标 */
	public static float[] rotate(float x, float y, float scalex, float scaley, float degree)
	{
		// 尺寸变化后的相对坐标
		x *= scalex;
		y *= scaley;
		
		// 逆时针旋转degree角度后的相对坐标
		degree %= 360;
		if ((x != 0 || y != 0) && degree != 0)
		{
			float x2 = x, y2 = y;
			double degree2 = -Math.PI * degree / 180;
			
			x2 = (float) (x * Math.cos(degree2) + y * Math.sin(degree2));
			y2 = (float) (y * Math.cos(degree2) - x * Math.sin(degree2));
			
			return new float[] { x2, y2 };
		}
		else
			return new float[] { x, y };
		
		// Log.e(degree + "度,坐标值:", ""+ x + "," + y);
	}
	
	// -------------------------------------------------完整调用树、异常代码位置信息输出------------------------------------------------
	
	/** 在LogCat中输出提示信息info,并给出输出该信息在代码中的完整调用树 */
	public static void StackTrace(String info)
	{
		StackTraceElement[] elem = Thread.currentThread().getStackTrace();	// 从当前位置,获取代码调用堆栈
		
		for (StackTraceElement e : elem)
		{
			String str = info + " 位置:" + e.getClassName() + " -> " + e.getMethodName() + "() 行:" + e.getLineNumber();
			Gdx.app.error(e.getFileName(), str);								// 输出调用位置信息和提示信息
			// Log.e(info, str);
			// System.out.println(info + "  " + str);
		}
	}
	
	// 当try块出错时,给出当前代码位置的,出错提示信息
	// try{}catch(Exception e){ Tools.Log("释放资源出错!"); }
	
	/** 在LogCat中输出提示信息info,并给出输出该信息在代码中的调用位置 */
	public static void Log(String info)
	{
		StackTraceElement[] elem = Thread.currentThread().getStackTrace();	// 从当前位置,获取代码的堆栈追踪信息
		
		StackTraceElement e = elem[3];										// 仅获取调用该函数的代码位置,不获取完整调用树
		String str = info + " 位置:" + e.getClassName() + " -> " + e.getMethodName() + "() 行:" + e.getLineNumber();
		Gdx.app.error(e.getFileName(), str);								// 输出调用位置信息和提示信息
		// Log.e(info, str);
		// System.out.println(info + "  " + str);
	}
	
	/** 在LogCat中输出提示信息info,并给出输出该信息在代码中的调用位置 */
	public static String getClassName()
	{
		StackTraceElement[] elem = Thread.currentThread().getStackTrace();	// 从当前位置,获取代码的堆栈追踪信息
		
		StackTraceElement e = elem[3];										// 仅获取调用该函数的代码位置,不获取完整调用树
		String str = e.getClassName();
		Gdx.app.error(e.getFileName(), str);								// 输出调用位置信息和提示信息
		
		return str;
		// Log.e(info, str);
		// System.out.println(info + "  " + str);
	}
	
	// -------------------------------------------------------------------------------------------------
	
	/** 获取对象e所在类名 */
	public static void getClassName(Object e)
	{
		Log.i("类名:", e.getClass().toString());
		
		// int i = 0;
		// Log.i("类型:", ((Object)i).getClass().toString()); ;
		// Log.i("类型:", e.getClass().getDeclaredFields()[0].getName());
	}
	
	public static void setAllComponentsName(Object e)
	{
		// 获取f对象对应类中的所有属性域
		Field[] fields = e.getClass().getDeclaredFields();
		for (int i = 0, len = fields.length; i < len; i++)
		{
			// 对于每个属性,获取属性名
			String varName = fields[i].getName();
			try
			{
				// 获取原来的访问控制权限
				boolean accessFlag = fields[i].isAccessible();
				// 修改访问控制权限
				fields[i].setAccessible(true);
				// 获取在对象f中属性fields[i]对应的对象中的变量 .get(e)
				Object o = fields[i].get(e);
				System.out.println("传入的对象中包含一个如下的变量: " + varName + " = " + o);
				// 恢复访问控制权限
				fields[i].setAccessible(accessFlag);
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
			}
		}
	}
}






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值