这里我的需求是:

1.对图片进行加密

2.要与AssetManager相结合

 

在搜索了网络上大部分的中文相关信息后,获得以下情报:

同时结合某个老外提到过的信息 https://www.it1352.com/117887.html

继承FileHandle,在其read方法时,对其后缀进行判断,如果是某特定后缀,进行加解密处理

相关类:

package com.zhfy.game.framework.tool;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.zhfy.game.config.ResConfig;
import com.zhfy.game.framework.ComUtil;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ImageFileHandle extends FileHandle {


    public ImageFileHandle(String fileName) {
        super(fileName);
    }


    @Override
    public InputStream read() {
        String suffix=super.file.getName();
        suffix=suffix.substring(suffix.lastIndexOf('.')+1);
        Gdx.app.log("","bin:"+suffix);
        if(suffix.equals("tata")){

            InputStream input = FileHandle.class.getResourceAsStream("/" + file.getPath().replace('\\', '/'));
            try {
                byte[] allBytes=  ComUtil.toByteArray(input);
                int byteCount = 0;
                for (int i = 0; i < allBytes.length; i++) {

                    // 每个字节异或密码,请保证解密时密码前后相同
                    byteCount++;
                    if (byteCount <= 20) {
                        // 加密20个字节,停止解密密
                        allBytes[i] ^= ResConfig.ImageKey.hashCode();
                    } else {
                        allBytes[i] = allBytes[i];
                    }
                }
                input= new ByteArrayInputStream(allBytes);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return input;
        }else {
            return super.read();
        }
    }

}
ImageFileHandle
package com.zhfy.game.framework.tool;

import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;

public class ImageFileHandleResolver implements FileHandleResolver {
    @Override
    public FileHandle resolve(String fileName) {
        return new ImageFileHandle(fileName);
    }


}
ImageFileHandleResolver
package com.zhfy.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.zhfy.game.framework.tool.ImageDecrypt;
import com.zhfy.game.framework.tool.ImageFileHandleResolver;

public class Armageddon extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;
    AssetManager am;
    boolean ifDraw;

    @Override
    public void create () {
        batch = new SpriteBatch();
        //ImageDecrypt i=new ImageDecrypt();
        am=new AssetManager(new 
                 ImageFileHandleResolver());
        //img = i.getTexture("badlogic.bin");
        am.load("badlogic.tata",Texture.class);
        ifDraw=false;
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        if(ifDraw){
            batch.draw(img, 0, 0);
        }else if(am.update()) {
            // updata()返回true,证明所有资源加载完成
            // 可以执行对应的操作了
            img=am.get("badlogic.tata",Texture.class);

            ifDraw=true;
        }
        batch.end();
    }

    @Override
    public void dispose () {
        batch.dispose();
        img.dispose();
        am.dispose();
    }
}
测试主类
    public static byte[] toByteArray(InputStream input)
            throws IOException
    {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        copy(input, output);
        return output.toByteArray();
    }

    public static int copy(InputStream input, OutputStream output)
            throws IOException
    {
        long count = copyLarge(input, output);
        if (count > 2147483647L) {
            return -1;
        }
        return (int)count;
    }

    public static long copyLarge(InputStream input, OutputStream output)
            throws IOException
    {
        byte[] buffer = new byte[4096];
        long count = 0L;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;

    }
inputStream的相关转换方法
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.PixmapIO;

/**
 * 加密GUI
 * 
 * @author 原作者方国
 * 
 */
public class Encryption {
    private static Frame frame = new Frame("加密解密工具");
    private TextField pathField = new TextField(20);
    private TextField keyField = new TextField(20);
    private JButton openButton = new JButton("加载文件");
    private JButton setPasswordButton = new JButton("修改密码");
    private JButton startButton = new JButton("开始加密");
    private static TextArea informationArea = new TextArea(100, 60);
    private static FileDialog pathFileDialog = new FileDialog(frame,
            "选择要加密的文件", FileDialog.LOAD);
    private static String key = "key";
    private static String path = "path";

    public void init() {
        frame.setBounds(200, 200, 480, 270);
        keyField.setText("请修改密钥,默认为:" + "key");

        openButton.addActionListener(new ActionListener() {
            // 加载文件
            @Override
            public void actionPerformed(ActionEvent e) {

                pathFileDialog.setVisible(true);
                pathField.setText("" + pathFileDialog.getDirectory()
                        + pathFileDialog.getFile());
                path = pathField.getText();
            }
        });
        setPasswordButton.addActionListener(new ActionListener() {
            // 修改秘钥
            
            @Override
            public void actionPerformed(ActionEvent arg0) {
                key =keyField.getText();
                JOptionPane.showMessageDialog(null, "                  恭喜您密钥修改成功!", 
                        "标题条文字串", JOptionPane.DEFAULT_OPTION);
            }
        });
        startButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e)  {

                if ("path".equals(path)) {
                    final Dialog tip = new Dialog(frame, true);
                    tip.setTitle("请加载文件");
                    Button button = new Button("请加载文件");
                    tip.add(button);
                    tip.setBounds(frame.getX() + frame.getWidth() / 2 - 70,
                            frame.getY() + frame.getHeight() / 2 - 40, 140, 80);

                    button.addActionListener(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent arg0) {
                            tip.setVisible(false);
                        }
                    });

                    tip.addWindowListener(new WindowAdapter() {
                        @Override
                        public void windowClosing(WindowEvent e) {
                            super.windowClosing(e);
                            tip.setVisible(false);
                        }
                    });
                    tip.setVisible(true);

                } else {
                    // 开始加密
                    File file = new File(pathFileDialog.getDirectory());
                    File[] files = file.listFiles();

                    for (int i = 0; i < files.length; i++) {
                        File inFile = null;
                        FileInputStream inputStream = null;

                        File outFile = null;
                        FileOutputStream outputStream = null;

                        try {

                            inFile = new File(files[i].getAbsolutePath());
                            inputStream = new FileInputStream(inFile);

                            outFile = new File(""
                                    + pathFileDialog.getDirectory()
                                    + getFileNameNoEx("" + inFile.getName())
                                    + ".tata");

                            while (outFile.exists()) {
                                if (!outFile.exists()) {
                                    outFile.createNewFile();
                                } else {
                                    outFile = new File(""
                                            + pathFileDialog.getDirectory()
                                            + getFileNameNoEx(""
                                                    + inFile.getName()) + i
                                            + ".tata");
                                    break;
                                }

                            }

                            outputStream = new FileOutputStream(outFile);

                            int value = -1;
                            // 加密20个字节
                            int byteCount = 0;
                            while ((value = inputStream.read()) != -1) {

                                // raf.write(value ^ key.hashCode());

                                // 每个字节异或密码,请保证解密时密码前后相同
                                byteCount++;
                                if (byteCount <= 20) {
                                    // 加密20个字节,停止加密
                                    outputStream.write(value ^ key.hashCode());
                                } else {
                                    outputStream.write(value);
                                }

                            }

                        } catch (FileNotFoundException e1) {
                            e1.printStackTrace();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        } finally {
                            try {

                                outputStream.close();
                                inputStream.close();

                            } catch (Exception e1) {
                                e1.printStackTrace();
                            }
                        }
                        informationArea.append(files[i].getName()
                                + " 加密完成!\n");

                    }
                    
                    
                }

            }
        });
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
        Panel panel = new Panel();
        panel.add(pathField);
        panel.add(openButton);

        Panel panel2 = new Panel();
        panel2.add(keyField);
        panel2.add(setPasswordButton);
        panel2.add(informationArea);

        Panel panel3 = new Panel();
        panel3.add(startButton);

        frame.add(panel, BorderLayout.NORTH);
        frame.add(panel2);
        frame.add(panel3, BorderLayout.SOUTH);
        frame.setVisible(true);

    }

    /**
     * 去掉文件扩展名
     * 
     * @param filename
     * @return
     */
    public static String getFileNameNoEx(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }

    public static void main(String[] args) {
        new Encryption().init();
    }
    

public String lastName(File file){
    if(file==null) return null;
    String filename = file.getName();
    if(filename.lastIndexOf(".")==-1){
        return "";//文件没有后缀名的情况
    }
    //此时返回的是带有 . 的后缀名,
    return filename.substring(filename.lastIndexOf("."));
 
    //return filename.subString(filename.lastIndexOf(".")+1);// 这种返回的是没有.的后缀名
    
    // 下面这种如果对于String类型可能有问题,如 以.结尾的字符串,会报错。但是文件没有以点结尾的
}
}
加密工具源码

 

测试结果

 

 -------------------------------------------------以上方法在安卓测试时会报找不到资源的错误,所以我参考另一种方法重写了loader方法,测试通过-------------------------------------------------

package com.zhfy.game.framework.tool;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetLoaderParameters;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.assets.loaders.TextureLoader;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.Array;
import com.zhfy.game.config.ResConfig;


public class EncryptTextureLoader extends AsynchronousAssetLoader<Texture, EncryptTextureLoader.TextureParameter> {


    public EncryptTextureLoader(FileHandleResolver resolver) {
        super(resolver);
    }

    @Override
    public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, TextureParameter parameter) {
        return null;
    }

    @Override
    public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter) {

    }

    @Override
    public Texture loadSync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter) {
        byte[] allBytes = file.readBytes();
        int byteCount = 0;
        for (int i = 0; i < allBytes.length; i++) {

            // 每个字节异或密码,请保证解密时密码前后相同
            byteCount++;
            if (byteCount <= 20) {
                // 加密20个字节,停止解密密
                allBytes[i] ^= ResConfig.ImageKey.hashCode();
            } else {
                allBytes[i] = allBytes[i];
            }
        }
        Pixmap   pixmap = new Pixmap(allBytes, 0, allBytes.length);
     Texture   texture = new Texture(pixmap);
        Gdx.app.log("加载特殊资源",fileName);
        return texture;
    }


    public class TextureParameter extends AssetLoaderParameters<Texture> {
    }
}
EncryptTextureLoader.java
assetManager=new AssetManager();
        assetManager.setLoader(Texture.class,
                ".tata",
                new EncryptTextureLoader(new InternalFileHandleResolver())
        );

 

测试ok:

 

 

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------

网络上的另一种实现思路:利用Assetmanager异步加载资源同时,以加载资源解密的实现实例:

https://download.csdn.net/download/kloxo/6504835?utm_source=bbsseo

由于相关配套文章丢失,只剩下源码(淘宝花了2块钱从csdn下载),所以发出给大家参考下

主源码:

package ghuazo.cipher;

import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetLoaderParameters;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.Gdx2DPixmap;
import com.badlogic.gdx.graphics.glutils.FileTextureData;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
/**
 * @author GhuaZo
 * 
 * QQ:137336521
 * 
 * 声明一下:
 *         本DEMO来自LIBGDX开发交流群 :145353767,转载切勿删除本提示
 */
public class CipherTextureLoader extends AsynchronousAssetLoader<Texture, CipherTextureLoader.TextureParameter>{

    public CipherTextureLoader(FileHandleResolver resolver) {
        super(resolver);
    }


    static public class TextureLoaderInfo {
        String filename;
        TextureData data;
        Texture texture;
    };
    TextureLoaderInfo info = new TextureLoaderInfo();

    
    public void loadAsync (AssetManager manager, String fileName, FileHandle file, TextureParameter parameter) {
        info.filename = fileName;
        if (parameter == null || parameter.textureData == null) {
            Pixmap pixmap = null;
            Format format = null;
            boolean genMipMaps = false;
            info.texture = null;

            if (parameter != null) {
                format = parameter.format;
                genMipMaps = parameter.genMipMaps;
                info.texture = parameter.texture;
            }

                
            pixmap = this.decipherPixmap(file);
            info.data = new FileTextureData(file, pixmap, format, genMipMaps);
            
        } else {
            info.data = parameter.textureData;
            if (!info.data.isPrepared()) info.data.prepare();
            info.texture = parameter.texture;
        }
    }

    public Texture loadSync (AssetManager manager, String fileName, FileHandle file, TextureParameter parameter) {
        if (info == null)
            return null;
        Texture texture = info.texture;
        if (texture != null) {
            texture.load(info.data);
        } else {
            texture = new Texture(info.data);
        }
        if (parameter != null) {
            texture.setFilter(parameter.minFilter, parameter.magFilter);
            texture.setWrap(parameter.wrapU, parameter.wrapV);
        }
        return texture;
    }

    private Pixmap decipherPixmap(FileHandle file){
        Gdx2DPixmap pixmap = null ; 
        short ff = (short)-128 ;
        try {
            byte[] bytes = file.readBytes();
            for(int i=0 ; i<bytes.length ; i++){
                bytes[i] = (byte) (bytes[i] ^ ff);
            }
            pixmap = new Gdx2DPixmap(bytes, 0, bytes.length, 0);
        } catch (Exception e) {
            throw new GdxRuntimeException("Couldn't load file: " + file, e);
        }
        return new Pixmap(pixmap) ; 
    }
    
    static public class TextureParameter extends AssetLoaderParameters<Texture> {
        /** the format of the final Texture. Uses the source images format if null **/
        public Format format = null;
        /** whether to generate mipmaps **/
        public boolean genMipMaps = false;
        /** The texture to put the {@link TextureData} in, optional. **/
        public Texture texture = null;
        /** TextureData for textures created on the fly, optional. When set, all format and genMipMaps are ignored */
        public TextureData textureData = null;
        public TextureFilter minFilter = TextureFilter.Nearest;
        public TextureFilter magFilter = TextureFilter.Nearest;
        public TextureWrap wrapU = TextureWrap.ClampToEdge;
        public TextureWrap wrapV = TextureWrap.ClampToEdge;
    }

    @Override
    public Array<AssetDescriptor> getDependencies(String fileName,
            FileHandle file, TextureParameter parameter) {
        // TODO Auto-generated method stub
        return null;
    }

    

    

}
CipherTextureLoader.java
package ghuazo.cipher;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
/**
 * @author GhuaZo
 * 
 * QQ:137336521
 * 
 * 声明一下:
 *         本DEMO来自LIBGDX开发交流群 :145353767,转载切勿删除本提示
 */
public class ImageCipher implements ApplicationListener {
    private SpriteBatch batch;
    private Texture texture;
    private AssetManager asset;

    @Override
    public void create() {
        this.batch = new SpriteBatch();
        this.asset = new AssetManager();
        this.asset.setLoader(Texture.class, 
                ".cpr",
                new CipherTextureLoader(new InternalFileHandleResolver())
        );
        this.asset.load("data/ghuazo.cpr", Texture.class);

    }

    @Override
    public void dispose() {
        batch.dispose();
        texture.dispose();
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        if (this.asset.update()) {
            this.texture = this.asset.get("data/ghuazo.cpr", Texture.class);
        }
        if (this.texture != null) {
            batch.begin();
            batch.draw(this.texture, 0, 0, Gdx.graphics.getWidth(),
                    Gdx.graphics.getHeight());
            batch.end();
        }

    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}
ImageCipher.java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
    <source path="ghuazo/cipher" />
</module>
ImageCipher.gwt.xml

工具代码:

package ghuazo.cipher;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
 * 
 * @author GhuaZo
 * QQ:137336521
 * 
 * 群里面总有好多人在讨论图片加密的问题,其实个人觉得没有什么必要,
 * 主要觉得图片解密很浪费资源,特别我们开发手机程序的时候,尽量不用;但是有人提出了就写个简单的小demo给大家提个思路
 * 关键是这个算法比较简单,运行时候消耗内存很小,缺点当然也有就是计算量(CPU)很大,这样涉及主要考虑到的就是手机游戏
 * 一般资源加载都是在程序运行之前采用异步加载方式,加载属于IO操作,这时候手机内存利用很高,而CPU几乎没有耗时运算,
 * 所以我们将我们的解密代码加载时候运行,算法比较简单,但是对于一般的人足够用了。
 * 声明一下:
 *         本DEMO来自LIBGDX开发交流群 :145353767,转载切勿删除本提示
 */
 

public class CipherMaker {

    private static short FF = (short)-128  ;
    
    public static void main(String args[]) throws Exception{
        
        //将123.jpg(明文)的图片加密到456.jpg(密文)
        cipher("D:\\123.png","D:\\ghuazo.png");
        System.out.println("将123.jpg(明文)的图片加密到ghuazo.png(密文)");
        //将456.jpg(密文)的图片解密成789.jpg(明文)
        //cipher("D:\\456.jpg","D:\\789.jpg");
        //System.out.println("将456.jpg(密文)的图片解密成789.jpg(明文)");
    }
    /**
     * 如果文件是明文文件输入,则输出加密的文件,如果输入的是加密的文件,则输出的是解密后的文件
     * @param inputPath
     * @param outputPath
     * @throws Exception
     */
    public static void cipher(String inputPath,String outputPath)throws Exception{
        //配合追加模式写文件
        File outFile = new File(outputPath);
        if(outFile.exists()){
            outFile.delete();
        }
        //追加模式写文件
        InputStream input = new FileInputStream(inputPath) ; 
        OutputStream output = new FileOutputStream(outputPath,true) ; 
        byte[] cacheBytes = new byte[1024];
        int cacheSize = 0;
        while ((cacheSize = input.read(cacheBytes)) > 0) {
            
            for(int i=0 ; i<cacheSize ; i++){
                cacheBytes[i] = (byte) (cacheBytes[i] ^ FF);
            }
            output.write(cacheBytes, 0, cacheSize);
        }
        input.close() ; 
        output.close() ; 
    
    }
    
}
CipherMaker.java

 

 

ps:该功能实现耗时3天.心累,还是推荐使用其他资料多的引擎吧,中文资料实在太少了.

posted on 2021-03-26 00:36  黑狱  阅读(205)  评论(0编辑  收藏  举报