Android:将位图保存为 bmp 文件格式

2024-01-06

我内存中有一个位图,我需要将其保存在 bmp 文件中(使用bmp 文件格式 http://en.wikipedia.org/wiki/BMP_file_format).

有什么办法可以在Android上做到这一点吗?

(我读了很多建议使用 png 格式的帖子 - 这是无损的 - 但是,这不是我需要的:我真的需要bmp 格式).

我已经有一些代码可以使用以下命令将其保存为 jpeg 或 png位图压缩 http://developer.android.com/reference/android/graphics/Bitmap.html#compress%28android.graphics.Bitmap.CompressFormat,%20int,%20java.io.OutputStream%29方法 :

/**
 * Save data to file using format.
 * When format is null : the bitmap will be saved in bmp format
 **/

public void writeBitmapToFile(Bitmap data, File file, Bitmap.CompressFormat format) {
    FileOutputStream os = null;
    try {
        os = new FileOutputStream(file);
        if(format==null){

            //TODO : write data to file using the bmp format

        }else{
            data.compress(format, 100, os); //ok for JPEG and PNG
        }
        os.flush();
    } catch (Exception e) {
        //irrelevant code
    } finally {
        //irrelevant code
    }
}

(我正在回答我自己的问题)

这是我当前的解决方案。它源自此来源:https://github.com/ultrakain/AndroidBitmapUtil https://github.com/ultrakain/AndroidBitmapUtil(感谢 ultrakain 和 @Francescoverheye )

我只是修复了必须添加到每行的虚拟字节计算中的一个小错误(以便每行的长度(以字节为单位)是 4 的倍数(根据 bmp 格式规范的要求)。

我还做了一些改变来提高性能。

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import android.graphics.Bitmap;
import android.util.Log;

public class AndroidBmpUtil {

    private static final int BMP_WIDTH_OF_TIMES = 4;
    private static final int BYTE_PER_PIXEL = 3;

    /**
     * Android Bitmap Object to Window's v3 24bit Bmp Format File
     * @param orgBitmap
     * @param filePath
     * @return file saved result
     */
    public static boolean save(Bitmap orgBitmap, String filePath) throws IOException {
        long start = System.currentTimeMillis();
        if(orgBitmap == null){
            return false;
        }

        if(filePath == null){
            return false;
        }

        boolean isSaveSuccess = true;

        //image size
        int width = orgBitmap.getWidth();
        int height = orgBitmap.getHeight();

        //image dummy data size
        //reason : the amount of bytes per image row must be a multiple of 4 (requirements of bmp format)
        byte[] dummyBytesPerRow = null;
        boolean hasDummy = false;
        int rowWidthInBytes = BYTE_PER_PIXEL * width; //source image width * number of bytes to encode one pixel.
        if(rowWidthInBytes%BMP_WIDTH_OF_TIMES>0){
            hasDummy=true;
            //the number of dummy bytes we need to add on each row
            dummyBytesPerRow = new byte[(BMP_WIDTH_OF_TIMES-(rowWidthInBytes%BMP_WIDTH_OF_TIMES))];
            //just fill an array with the dummy bytes we need to append at the end of each row
            for(int i = 0; i < dummyBytesPerRow.length; i++){
                dummyBytesPerRow[i] = (byte)0xFF;
            }
        }

        //an array to receive the pixels from the source image
        int[] pixels = new int[width * height];

        //the number of bytes used in the file to store raw image data (excluding file headers)
        int imageSize = (rowWidthInBytes+(hasDummy?dummyBytesPerRow.length:0)) * height;
        //file headers size
        int imageDataOffset = 0x36; 

        //final size of the file
        int fileSize = imageSize + imageDataOffset;

        //Android Bitmap Image Data
        orgBitmap.getPixels(pixels, 0, width, 0, 0, width, height);

        //ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
        ByteBuffer buffer = ByteBuffer.allocate(fileSize);

        /**
         * BITMAP FILE HEADER Write Start
         **/
        buffer.put((byte)0x42);
        buffer.put((byte)0x4D);

        //size
        buffer.put(writeInt(fileSize));

        //reserved
        buffer.put(writeShort((short)0));
        buffer.put(writeShort((short)0));

        //image data start offset
        buffer.put(writeInt(imageDataOffset));

        /** BITMAP FILE HEADER Write End */

        //*******************************************

        /** BITMAP INFO HEADER Write Start */
        //size
        buffer.put(writeInt(0x28));

        //width, height
        //if we add 3 dummy bytes per row : it means we add a pixel (and the image width is modified.
        buffer.put(writeInt(width+(hasDummy?(dummyBytesPerRow.length==3?1:0):0)));
        buffer.put(writeInt(height));

        //planes
        buffer.put(writeShort((short)1));

        //bit count
        buffer.put(writeShort((short)24));

        //bit compression
        buffer.put(writeInt(0));

        //image data size
        buffer.put(writeInt(imageSize));

        //horizontal resolution in pixels per meter
        buffer.put(writeInt(0));

        //vertical resolution in pixels per meter (unreliable)
        buffer.put(writeInt(0));

        buffer.put(writeInt(0));

        buffer.put(writeInt(0));

        /** BITMAP INFO HEADER Write End */

        int row = height;
        int col = width;
        int startPosition = (row - 1) * col;
        int endPosition = row * col;
        while( row > 0 ){
            for(int i = startPosition; i < endPosition; i++ ){
                buffer.put((byte)(pixels[i] & 0x000000FF));
                buffer.put((byte)((pixels[i] & 0x0000FF00) >> 8));
                buffer.put((byte)((pixels[i] & 0x00FF0000) >> 16));
            }
            if(hasDummy){
                buffer.put(dummyBytesPerRow);
            }
            row--;
            endPosition = startPosition;
            startPosition = startPosition - col;
        }

        FileOutputStream fos = new FileOutputStream(filePath);
        fos.write(buffer.array());
        fos.close();
        Log.v("AndroidBmpUtil" ,System.currentTimeMillis()-start+" ms");

        return isSaveSuccess;
    }

    /**
     * Write integer to little-endian
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeInt(int value) throws IOException {
        byte[] b = new byte[4];

        b[0] = (byte)(value & 0x000000FF);
        b[1] = (byte)((value & 0x0000FF00) >> 8);
        b[2] = (byte)((value & 0x00FF0000) >> 16);
        b[3] = (byte)((value & 0xFF000000) >> 24);

        return b;
    }

    /**
     * Write short to little-endian byte array
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeShort(short value) throws IOException {
        byte[] b = new byte[2];

        b[0] = (byte)(value & 0x00FF);
        b[1] = (byte)((value & 0xFF00) >> 8);

        return b;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android:将位图保存为 bmp 文件格式 的相关文章

  • 如何在谷歌地图android上显示多个标记

    我想在谷歌地图android上显示带有多个标记的位置 问题是当我运行我的应用程序时 它只显示一个位置 标记 这是我的代码 public class koordinatTask extends AsyncTask
  • 使用片段时应用程序崩溃

    我正在处理碎片和 我的代码中有一个我找不到的问题 logcat 指向我的一个片段中的这段代码 Override public View onCreateView LayoutInflater inflater ViewGroup conta
  • 获取文件的总大小(以字节为单位)[重复]

    这个问题在这里已经有答案了 可能的重复 java 高效获取文件大小 https stackoverflow com questions 116574 java get file size efficiently 我有一个名为 filenam
  • Android 2.3 模拟器在更新位置时崩溃

    我正在使用 Eclipse 编写和调试 Android 应用程序 我需要做的事情之一是更新设备的位置 因此我尝试使用模拟器控制窗口中的位置控制面板 在 手动 选项卡上 我选择 十进制 输入有效的纬度和经度 然后单击 发送 不幸的是 接下来发
  • 如何在 Android 中从 WorkManager 取消工作?

    我已经保存了 WorkManagerUUID转换成String在领域数据库中 这是代码 Constraints constraints new Constraints Builder setRequiredNetworkType Netwo
  • Android:无法使用 DbHelper 和 Contract 类将数据插入 SQLite

    public class Main2Activity extends AppCompatActivity private EditText editText1 editText2 editText3 editText4 private Bu
  • Eclipse 启动时崩溃;退出代码=13

    I am trying to work with Eclipse Helios on my x64 machine Im pretty sure now that this problem could occur with any ecli
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • 如何检查 Android 中的同步设置

    我正在构建一个 Android 应用程序 我需要检查设备中注册的每个单独帐户的同步设置 我知道我可以通过 ContentResolver 类来做到这一点 但我遇到了一些问题 我已设法获取设备上所有帐户的列表 但我不知道在运行时从哪里获取特定
  • Android - 以编程方式选择菜单选项

    有没有办法以编程方式选择菜单选项 基本上 我希望视图中的按钮能够执行与按特定菜单选项相同的操作 我正在考虑尝试调用 onOptionsItemSelected MenuItem item 但我不知道要为菜单项添加什么 是的 有一种方法可以选
  • 没有用于警告的设置器/字段 Firebase 数据库检索数据填充列表视图

    我只是想将 Firebase 数据库中的数据填充到我的列表视图中 日志显示正在检索数据 但适配器不会将值设置为列表中单个列表项中的文本 它只说 没有二传手 场地插入值 这让我觉得我的设置器没有正确制作 但 Android Studio 自动
  • 找不到符号 NOTIFICATION_SERVICE?

    package com test app import android app Notification import android app NotificationManager import android app PendingIn
  • 如何使用mockito模拟构建器

    我有一个建造者 class Builder private String name private String address public Builder setName String name this name name retur
  • 问题:为什么React Native Video不能全屏播放视频?

    我正在react native 0 57 7 中为android和ios创建一个应用程序并使用反应本机视频 https github com react native community react native video播放上传到的视频
  • 使用反射覆盖最终静态字段是否有限制?

    在我的一些单元测试中 我在最终静态字段上的反射中遇到了奇怪的行为 下面是说明我的问题的示例 我有一个基本的 Singleton 类 其中包含一个 Integer public class BasicHolder private static
  • 没有支持 FEATURE_CAMERA_EXTERNAL 的 Android 设备

    根据this doc https source android com devices camera external usb cameras一些 Android 设备允许使用 Camera2 API 访问外部 USB 摄像头 我检查了大约
  • 如何将双精度/浮点四舍五入为二进制精度?

    我正在编写对浮点数执行计算的代码的测试 不出所料 结果很少是准确的 我想在计算结果和预期结果之间设置一个容差 我已经证实 在实践中 使用双精度 在对最后两位有效小数进行四舍五入后 结果始终是正确的 但是usually四舍五入最后一位小数后
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类
  • Git 实验分支还是单独的实验存储库?

    我正在开发一个 Android 应用程序 并且在整个开发周期中一直使用 Git 现在 我想构建并发布实验性功能 供人们尝试和安装 同时仍将原始的 稳定的应用程序安装在他们的设备上 现在 这意味着我需要使用不同的包名称 这会更改开发项目中的一

随机推荐

  • jQuery UI Accordion - 如何完全删除样式?

    我喜欢 jQuery 手风琴 http jqueryui com demos accordion 的功能 但是我不想要这种风格 我想摆脱所有的样式 img 边框 颜色等 我没有看到这个选项 这是他们应该添加的内容 还是我误会了 您可以制作自
  • linux下c语言蓝牙编程

    我正在尝试在 linux ubuntu 中运行基本的 c 代码来搜索蓝牙设备 但我遇到了一些问题 通过使用命令sudo apt get install bluez 要安装所需的blueZ库 说明bluez已经是最新版本了 但出现错误 无法找
  • PHP 正则表达式查找自定义添加的 HTML 标签之间的文本

    我有以下场景 Got an HTML模板将用于的文件mailing 这是一个简化的示例 table tr td Heading 1 td td heading 2 td tr table
  • http.sys 实现

    我们都知道有一个名为 http sys 的二进制文件内核模式驱动程序在我们的 Windows 中 它为我们进行 HTTP 处理 这基本上就是我们所知道的一切 但今天我想 嘿 我们所有的网络东西 比如 TCP IP 之类的东西都在这里 在用户
  • 有充分的理由不使用 ORM 吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 查找并迭代android中的所有短信/彩信

    首先 也是最重要的 我发现了这个answer https stackoverflow com a 6446831 2415237特别有帮助 然而 这让我想知道如何找到这些信息 我似乎不知道如何迭代收件箱中的所有消息 我当前的解决方案使用Ur
  • Clearerr 是用来做什么的?

    我试图了解 stdio 功能何时clearerr 应该使用 例如 如果我fread or fwrite 在有效的FILE 并得到一个简短的计数ferror是真的 我能做什么 从我到目前为止所读到的来看 fread and fwrite 很健
  • 打字稿:找不到名称“代理”

    我需要声明一个 Proxy 类型的新变量 来自 ES6 规范 myProxy Proxy 但我收到下一个错误 找不到名称 代理 我该如何修复它 假设您将目标设置为es2015或包括库es2015使用lib选项 您可以创建一个Proxy 诀窍
  • 更新包并防止其恢复为原始状态

    我想升级包 ggplot2 library ggplot2 packageDescription ggplot2 Version gt 0 8 3 但当前版本是0 8 7 我尝试了 update packages 它似乎工作正常 但它仍然返
  • 如何获取临时文件名?

    我看过一些与我的问题相关的帖子 但没有一个能完全解决这个问题 我需要在标准临时目录中创建一个文件 完成写入后 将其移动到其他位置 这个想法是 该文件在下载时被视为临时文件 在下载完成后被视为永久文件 我正在尝试通过致电mkstemp htt
  • 将数据从一个纬度经度网格插入到另一个纬度经度网格上?

    我有两个位于经纬度网格上的数据数组 第一个 A 的形状为 89 180 第二个 B 的形状为 94 192 A 的纬度按降序排列 从 88 到 88 经度按升序从 0 到 358 B 的纬度按降序从 88 54199982 到 88 541
  • CNCopyCurrentNetworkInfo 不适用于 iOS 14

    我有一个使用 WIFI 连接到外部设备的应用程序 我曾经通过检查 WIFI SSID 来验证 iPhone 是否已连接到该设备 当 iOS 13 发布时 这个问题被阻止了 我通过请求位置权限来获取 SSID 来修复它 我现在尝试使用启用了位
  • 为什么sed命令包含at符号

    我不明白为什么以下 sed 命令包含 符号 sed s session s required s pam loginuid so session optional pam loginuid so g i etc pam d sshd 我查看
  • ReactJS 给出 inst.render 不是函数错误

    当我用 React 和 ReactDOM 展示一个非常基本的 Hello World 时 我遇到了一个奇怪的错误Uncaught TypeError inst render is not a function 在此查看JSBin https
  • 正则表达式“(?

    我花了大约三个小时试图理解如何
  • Websocket 可扩展性、广播问题

    如果您有一个包含许多用户 和服务器 的复杂要求 您的 websocket 基础设施 服务器 将如何扩展 尤其是广播 当然 广播不是任何 websocket 规范的一部分 但它甚至存在于基本的聊天示例中 又名 websocket 的 hell
  • Java 泛型有没有办法获取需要实现 2 个接口的泛型参数?

    假设我有这个代码 public interface ParentInterface1 public List
  • 使用 javascript 平滑自动滚动

    我正在尝试在网页上实现一些代码 以在加载页面后自动滚动 我使用Javascript函数来执行自动滚动 并在页面加载时调用我的函数 但页面仍然滚动不顺畅 有什么办法可以自动平滑地滚动我的页面吗 这是我的 JavaScript 函数 funct
  • 循环多维数组时出现问题

    我在尝试使用 PHP 循环多维数组时遇到问题 当我使用print r 函数 这是我的输出 Array 0 gt Array fname gt sname gt address gt address2 gt city gt state gt
  • Android:将位图保存为 bmp 文件格式

    我内存中有一个位图 我需要将其保存在 bmp 文件中 使用bmp 文件格式 http en wikipedia org wiki BMP file format 有什么办法可以在Android上做到这一点吗 我读了很多建议使用 png 格式