文档章节

libpng error: Not a PNG file

virjar
 virjar
发布于 2017/08/30 17:49
字数 725
阅读 100
收藏 0

aapt在处理png文件的时候,会判定文件类型,如果不是png,将会抛出此错误。出现这个问题的原因是我们很多时候凭感觉手动将jpeg之类的其他文件后缀名强制修改为png,这个时候看图软件仍然能够识别图片。但是aapt却不识别,导致编译失败。

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

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

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

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#aaptPackage

之后,编译即可通关

© 著作权归作者所有

上一篇: dungproxy
下一篇: dungproxy
virjar
粉丝 5
博文 2
码字总数 1162
作品 3
成都
私信 提问

暂无文章

006-Sigle-基于blockstack去中心化博客

本篇文章主要讲解有关基于Blockstack的Sigle是一个去中心化的博客项目; 官网地址:https://www.sigle.io/ Github地址:https://github.com/pradel/sigle 页面展示: 介绍: A beautiful de...

Riverzhou
23分钟前
9
0
驰骋工作流引擎开发平台属性功能的隐藏显示介绍

关键字: 工作流程管理系统 工作流引擎 asp.net工作流引擎 java工作流引擎. 表单引擎 工作流功能说明 工作流设计 工作流快速开发平台 业务流程管理 bpm工作流系统 java工作流主流框架 自定义...

孟娟
25分钟前
8
0
MyBatis binding 模块分析

MyBatis binding 模块分析 binding功能代码所在包 org.apache.ibatis.binding binding模块作用 封装ibatis编程模型 ibatis编程模型中,SqlSession作为sql执行的入口,实用方法为sqlSession.se...

红妍落日
27分钟前
7
0
网易互娱的数据库选型和 TiDB 应用实践

作者介绍:李文杰,网易互娱计费组,高级数据库管理工程师,TiDB User Group Ambassador。 一、业务架构简介 计费组是为网易互娱产品提供统一登录和支付高效解决方案的公共支持部门,对内是互...

TiDB
34分钟前
8
0
Debezium接入Mysql遇到到的Tinyint坑

问题背景: 在Debezium做数据初始化的时候,对于一些tinyint字段的值,出现0,1的值的异常。 经过源码排查,数据在JDBC上面,读取到的数据是Boolean值。 通过排查,原来是MYSQL特有的数据问题...

吐槽的达达仔
42分钟前
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部