Android JPG格式图片强转为16位BMP格式图片

        之前有个需求是服务器上传图片来设置开机LOGO,但是系统限制LOGO图片必须是16位的BMP图片格式,服务器上传的图片不仅包含BMP图片,还包含了JPG的图片格式,因此需要将JPG格式的图片转换成16位的BMP格式。

        BMP图片数据实际也是一位位的0和1组成,因此我们可以将JPG格式的图片转换成Bitmap对象,再遍历其中的每个像素点,将对应的颜色信息转换成实际数字,并写入BMP图片文件中。

        同时BMP文件不仅包含了像素颜色信息,还要有对应的文件头来表示文件格式等信息;如果图片分辨率和颜色深度不变的话,这些信息都是固定的,也是可以直接写入文件中,这里我的图片格式需求是1920*1080 16位颜色深度。

        首先转换JPG图片为Bitmap对象。

        FileInputStream in = null;
        try {
            in = new FileInputStream("/storage/emulated/0/Pictures/bootup.jpg");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        Bitmap bitMap = BitmapFactory.decodeStream(in); //由输入流获取Bitmap对象  操作图片

        /*改变图片大小*/
        int width = bitMap.getWidth();    //原始宽度
        int height = bitMap.getHeight();    //原始高度
        int newWidth = 1920;             //需求宽度
        int newHeight = 1080;               //需求高度
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);   //  缩放图片
        bitMap = Bitmap.createBitmap(bitMap, 0, 0, width, height, matrix, true); //获取最终修改完成之后的Bitmap对象

        通过位运算将32位颜色信息转换为16位。

    public void convertBitmapTo16BitBMP(Bitmap bitmap, String outputPath) throws IOException {
        // 将Bitmap转换为ARGB_8888格式
        if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
            bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
        }
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] pixels = new int[width * height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

        // 创建一个新的16位bmp文件
        FileOutputStream fos = new FileOutputStream(outputPath);

        // 写入bmp文件头
        int bfType = 0x4d42;
        long bfSize = 56 + (long) width *height*2 + ((long) width *height*2)%4;
        int bfReserved1 = 0;
        int bfReserved2 = 0;
        long bfOffBits = 54;
        // 保存bmp文件头
        writeWord(fos, bfType);
        writeDword(fos, bfSize);
        writeWord(fos, bfReserved1);
        writeWord(fos, bfReserved2);
        writeDword(fos, bfOffBits);
        // bmp信息头
        long biSize = 40L;
        int biPlanes = 1;
        int biBitCount = 16;
        long biCompression = 0L;
        long biSizeImage = 2+(long) width *height*2 + ((long) width *height*2)%4;
        long biXpelsPerMeter = 11815L;
        long biYPelsPerMeter = 11815L;
        long biClrUsed = 0L;
        long biClrImportant = 0L;
        // 保存bmp信息头
        writeDword(fos, biSize);
        writeLong(fos, width);
        writeLong(fos, height);
        writeWord(fos, biPlanes);
        writeWord(fos, biBitCount);
        writeDword(fos, biCompression);
        writeDword(fos, biSizeImage);
        writeLong(fos, biXpelsPerMeter);
        writeLong(fos, biYPelsPerMeter);
        writeDword(fos, biClrUsed);
        writeDword(fos, biClrImportant);

        // 遍历Bitmap的每个像素,将其颜色值从32位减少到16位
        for( int i = height-1;i >=0;i--) {
            for (int j =0;j<width;j++) {
                int color = pixels[i*width+j];

                int red = Color.red(color);
                int green = Color.green(color);
                int blue = Color.blue(color);
                int alpha = Color.alpha(color);

                // 将颜色值从32位减少到16位
                int newColor = ((red >> 3) << 10) | ((green >> 3) << 5) | (blue >> 3);
                fos.write(Integer.valueOf(newColor).byteValue());
                fos.write(Integer.valueOf((newColor >> 8)).byteValue());
            }
        }
        fos.close();
    }

         这样我们就得到一个固定大小的16位BMP格式图片,实际上,通过类似的方法,我们还可以转换Bitmap为更高位深的24位BMP图片,只需要简单修改一下BMP信息头和遍历时的位运算即可。

        但是最后得到的图片却不能成功设置为开机LOGO,通过文件比较工具发现,实际上的LOGO文件文件头与我们转换写入的文件头有几位数不同,并且像素位也相差几位,查阅资料发现可能是与图片的加密压缩有关,这里就不再深入探究了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值