java - 如何从大量值创建缩放图像

标签 java android arrays canvas bitmap

我正在根据使用媒体播放器录制时从麦克风获取的音量值列表创建波形图像。

这对于几分钟长的录音非常有效,但当录音大约一个小时时,我会收到内存不足错误。

我知道这个错误来 self 的代码,我在其中尝试创建位图图像,宽度(以像素为单位)是数组的长度,高度始终为 200 像素。

请有人帮我创建一个方法,该方法可以接受 n 长度的大型 int 值(从 0 - 100)数组,并创建缩放的位图图像?

我知道我最好运行数组的较小块并从中创建缩放图像,然后可能以某种方式将其附加到主缩放图像上,但我正在挣扎。

这是我的代码:

    public void generateWaveFormImage() {
    try {
        mBitmap = Bitmap.createBitmap(waveValues.size(), 200, Bitmap.Config.RGB_565);
        canvas = new Canvas(mBitmap);

        for(int i=0; i<waveValues.size(); i++) {
            canvas.drawLine(i, 100, i, 100-(int)waveValues.get(i), paint);
            canvas.drawLine(i, 100, i, 100 + (int) waveValues.get(i), paint);
        }

        Bitmap resized = Bitmap.createScaledBitmap(mBitmap, 760, 200, true);
        FileManager.saveImage(mShortNameWaveImage, resized);

    } catch(Exception e) {}
    waveValues = new ArrayList();
}

这对于较小的录音非常有效,即当 waveValues 数组中存储了 2000 个值时。

这是抛出内存不足错误的行

    mBitmap = Bitmap.createBitmap(waveValues.size(), 200, Bitmap.Config.RGB_565);

我想添加到目前为止我尝试过的内容。

假设 waveValues 数组的长度为 3500。

我采用前 1000 个值,创建一个 1000 x 200 图像并将值写入该图像,然后缩小到 760 X 200 并保存。

然后,我采用接下来的 1000 个值并执行相同的操作,然后将它们附加在一起,并将图像重新缩放至 760 x 200。

然后,我获取接下来的 1000 个值,执行相同的操作,并将其附加到主图像上,重新缩放到 760,然后对最后 500 个值执行相同的操作。

这会导致创建一个不正确缩放的图像,前两个图像缩放得太多,第三个图像是正确的,最后一个图像缩放到更大的图像,这会产生非常奇怪和美妙的波形。

最佳答案

内存中位图的存储没有压缩,在 RGB_565 中,每个点 2 个字节,如果您的图像是 2000 宽度 * 200 高度 = 400k 点 *2 = 800 KB 数据 - 在更大的图像上您应该会出现 OOM 错误。 无论如何,您必须在绘制之前重新缩放数据,而不是之后 - 绘制全尺寸点然后依靠特定于图像的重新缩放方法有什么用?

double scaleFactor = (double) 760/waveValues.size(); //This will fit all your points inside 760px resolution
for(int i=0; i<waveValues.size(); i++) {
        canvas.drawLine((int) (i*scaleFactor), 100, (int) (i*scaleFactor), 100 - (int)waveValues.get(i), paint);
        canvas.drawLine((int) (i*scaleFactor), 100, (int) (i*scaleFactor), 100 + (int)waveValues.get(i), paint);
    }

当然,您可以通过一次绘制操作将速度提高一倍:

double scaleFactor = (double) 760/waveValues.size(); //This will fit all your points inside 760px resolution
for(int i=0; i<waveValues.size(); i++) {
        canvas.drawLine((int) (i*scaleFactor), 100 - (int)waveValues.get(i), (int) (i*scaleFactor), 100 + (int)waveValues.get(i), paint);           
    }

现在,如果有 76 个点,每条线的宽度将为 10px。

如果有 7600 个点,每条线的宽度将为 0.1 像素,因此 1 像素中有 10 条线

并且您的图像将始终保持在 760x200 范围内

顺便说一句,您应该确保您的值始终在 0..100 之内,否则您将出现剪切(线条将落在图片之外)

关于java - 如何从大量值创建缩放图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45147131/

相关文章:

Java SwingWorker从数据库加载数据到List

android - 当手机处于休眠状态或 Activity (用于启动服务)未运行时,服务不应停止

android - SD 卡写入是否被阻止?

ios - 难以理解数组追加

javascript - 输出好友姓名而不是 ID

java - 触摸输入和 OpenJDK 11 与 JavaFX 11 的问题

java - 如何命名这样的复合类?

java - JDBC PrepareStatement 参数不适用于 CREATE、DROP、ALTER

java - 图像资源在 Android 中给出 0

c++ - 如果用户越界,我想忽略他们的输入