libpng error: Not a PNG file

aapt在处理png文件的时候,会断定文件类型,若是不是png,将会抛出此错误。出现这个问题的缘由是咱们不少时候凭感受手动将jpeg之类的其余文件后缀名强制修改成png,这个时候看图软件仍然可以识别图片。可是aapt却不识别,致使编译失败。java

使用as正向构建android工程的时候,能够设置aapt参数忽略png。android

可是使用apkTool回编的时候,没有设置入口,由于只要有此问题发送,其命令行返回类型就是1(非正常退出)。apache

在执行aapt命令的时候,先行修复全部存在此问题的png文件,避免aapt阻断。方案以下:app

1.实现转化类

package brut.util;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Created by virjar on 2017/8/30. 修复png文件格式
 * 
 * <pre>
 *     libpng error: Not a PNG fileERROR: Failure processing PNG image /Users/virjar/Desktop/9candroid/com.china3s.android_635/res/drawable/xprod_arrow_green.png
 * </pre>
 * 
 * 该错误会致使aapt命令返回1(非正常返回值),致使apk阻断。本工具读取全部.png结尾的图片,若是发现他不是png,则尝试转化为png格式文件
 */
public class PNGRepair {
    public static void repair(File file) {
        if (file == null) {
            return;
        }
        if (!file.exists()) {
            return;
        }
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files == null) {
                return;
            }
            for (File subFile : files) {
                repair(subFile);
            }
            return;
        }

        if (!StringUtils.endsWithIgnoreCase(file.getPath(), ".png")) {
            // 不是png不处理
            return;
        }

        ImageTypeBufferedInputStream imageTypeBufferedInputStream = null;
        try {
            imageTypeBufferedInputStream = new ImageTypeBufferedInputStream(new FileInputStream(file));
            if (StringUtils.equalsIgnoreCase(imageTypeBufferedInputStream.mType, "png")) {
                return;// 自己就是png文件,忽略处理
            }

            System.out.println(
                    "file: " + file.getPath() + " is a " + imageTypeBufferedInputStream.mType + "  transfer to png");

            BufferedImage bufferedImage = ImageIO.read(imageTypeBufferedInputStream);
            IOUtils.closeQuietly(imageTypeBufferedInputStream);// close stream advance

            ImageIO.write(bufferedImage, "png", file);
        } catch (IOException e) {
            e.printStackTrace();// ignore
        } finally {
            // make sure stream is closed
            IOUtils.closeQuietly(imageTypeBufferedInputStream);
        }

    }

    private static class ImageTypeBufferedInputStream extends InputStream {
        private InputStream delegate;

        private byte[] type = new byte[4];

        private byte cursor = 0;

        private String mType;

        ImageTypeBufferedInputStream(InputStream delegate) throws IOException {
            this.delegate = delegate;
            int read = delegate.read(type, 0, type.length);
            if (read < 4) {
                mType = "unknown";
                return;
            }

            String s = bytesToHexString(type).toUpperCase();
            if (StringUtils.equals(s, "FFD8FFE1")) {
                mType = "jpg";
            } else if (StringUtils.equals(s, "89504E47")) {
                mType = "png";
            } else if (StringUtils.equals(s, "47494638")) {
                mType = "gif";
            } else if (StringUtils.equals(s, "424D0890")) {
                mType = "bmp";
            } else {
                mType = "unknown";
            }

        }

        private static String bytesToHexString(byte[] src) {
            StringBuilder stringBuilder = new StringBuilder();
            if (src == null || src.length <= 0) {
                return "";
            }
            for (byte aSrc : src) {
                int v = aSrc & 0xFF;
                String hv = Integer.toHexString(v);
                if (hv.length() < 2) {
                    stringBuilder.append(0);
                }
                stringBuilder.append(hv);
            }
            return stringBuilder.toString();
        }

        @Override
        public int read() throws IOException {
            if (cursor < 4) {
                return type[cursor++];
            }
            return delegate.read();
        }

        @Override
        public long skip(long n) throws IOException {
            return delegate.skip(n + 4 - cursor);
        }

        @Override
        public int available() throws IOException {
            return delegate.available() + cursor - 4;
        }

        @Override
        public void close() throws IOException {
            delegate.close();
        }

        @Override
        public synchronized void mark(int readlimit) {
            delegate.mark(readlimit);
        }

        @Override
        public synchronized void reset() throws IOException {
            delegate.reset();
        }

        @Override
        public boolean markSupported() {
            return delegate.markSupported();
        }
    }
}

2.在apktool编译资源文件的流程中,加入修复逻辑调用

public void aaptPackage(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include)
            throws AndrolibException {

        boolean customAapt = false;
        String aaptPath = apkOptions.aaptPath;
        List<String> cmd = new ArrayList<String>();

        //convert png file
        //TODO add switch
        LOGGER.info("convert png file, to avoid \"libpng error: Not a PNG fileERROR\" from aapt");
        PNGRepair.repair(resDir);//在这里加入修复代码

        // path for aapt binary
        if (! aaptPath.isEmpty()) {
            File aaptFile = new File(aaptPath);
            if (aaptFile.canRead() && aaptFile.exist
.....

流程方法全称为:brut.androlib.res.AndrolibResources#aaptPackageide

以后,编译便可通关工具

相关文章
相关标签/搜索