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

以後,編譯便可通關工具

相關文章
相關標籤/搜索