首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何确定BitmapFactory.decodeStream是否已完成从套接字InputStream解码图像?

如何确定BitmapFactory.decodeStream是否已完成从套接字InputStream解码图像?
EN

Stack Overflow用户
提问于 2022-01-26 09:20:34
回答 2查看 280关注 0票数 0

我正在开发一个通过BluetoothSocket接收图像的安卓应用程序,我试图通过使用BitmapFactory.decodeStream()方法检索其Bitmap,如下所示:

代码语言:javascript
运行
复制
// Create BluetoothSocket socket and connect
// ...

// Get input stream
InputStream inputStream = socket.getInputStream();

// Get image bitmap
Bitmap bmp = BitmapFactory.decodeStream(inputStream);

所发生的情况是,应用程序被困在BitmapFactory.decodeStream()上。要永远停止应用程序挂起,我必须从远程设备手动关闭套接字,只有在此之后图像才会被成功解码和返回,但对于我的应用程序来说,这不是一个可行的解决方案,因为我希望以编程方式传输图像。我尝试过的另一件事是创建一个单独的Thread并在其中调用decodeStream(),然后用硬编码的时间调用Thread.start(),然后用硬编码的时间等待,然后再终止线程。这是可行的,但我想避免这样做有两个原因:

  • 我希望传输尽可能快,但在这种情况下,如果映像小于预期,则线程所需时间比所需时间要长。
  • 如果映像比预期的要大,则线程可能会在数据仍在处理时完成,从而造成一些数据丢失。

我查看了文档,希望在解码图像之前找到一种方法来初步设置预期的图像大小,这样应用程序就可以知道数据何时被正确地接收到了,比如:

代码语言:javascript
运行
复制
// Estimate length of expected data (size of image in bytes)
byte[] numOfBytes = new byte[inputStream.available()];
inputStream.read(numOfBytes)

// Set preliminary options
BitmapFactory.Options options = new BitmapFactory.Options();
options.setExpectedImageSize(numOfBytes)          // what I would ideally want: set fixed number of bytes 
                                                  // to let the BitmapFactory.decodeStream() method know when
                                                  // the decoding is over

// Get image bitmap
Bitmap bmp = BitmapFactory.decodeStream(inputStream, null, options);

但这样的程序似乎并不存在。

我有办法做到这一点吗?

服务器端(C#)

代码语言:javascript
运行
复制
// Create bluetooth socket 
// ...

DataWriter writer = new DataWriter(socket.OutputStream);

// Send image byte array
writer.WriteBytes(imageByteArray);
await writer.StoreAsync();
await writer.FlushAsync();

writer.Dispose();
socket.Dispose();

客户端(Java)

代码语言:javascript
运行
复制
// Create bluetooth socket and connect
// ...

InputStream inputStream = socket.getInputStream();

Bitmap bmp = BitmapFactory.decodeStream(inputStream);

return bmp;

已发送:

已收到:

EN

回答 2

Stack Overflow用户

发布于 2022-01-26 09:57:07

当BitmapFactory.decodeStream()准备就绪时,它将关闭流。因此插座也会关闭。你说它挂了?我们..。嗯嗯。嗯。

这就是为什么我早些时候说过,服务器应该在发送文件之后关闭套接字。是什么原因导致我的图像在传输期间损坏通过蓝牙RFCOMM使用FTP?

如果希望在发送/接收图片后保持连接打开,则不能使用BitmapFactory.decodeStream()。-

希望能在解码图像之前,找到一种初步设定图像大小的方法,

嗯,这是相当标准的。您让服务器首先发送一个整数(4个字节),指示以下字节的长度/数量。

客户端首先读取该整数,并可以创建一个大小合适的字节数组,将文件的接收字节放在其中。然后可以使用BitmapFactory.decodeByteArray()。(或者类似的事情)。

票数 0
EN

Stack Overflow用户

发布于 2022-01-26 14:26:34

如果decodeStream没有完成,这很可能意味着它试图读取的InputStream已经阻塞。这意味着它还没有收到预期的数据。

还有另一个可能的解释:服务器可能发送格式错误的图像,导致解码器被卡在客户端。Java 5图像解码器中的一个例子.很久很久以前..。是CVE-2006-6745。可能还有更近期的。

显然,不同于Java图像解码器类,Android的decodeStream 不调用这意味着,除了检查它返回的decodeStream 的值之外,没有任何方法可以判断调用是否已经完成。javadoc指出:

“如果输入流为null,或者不能用于解码位图,则函数返回null。在读取编码数据之后,该流的位置将一直保持在原来的位置。”

但我觉得你真的没抓住重点。如果我错了,请纠正我,但实际上您要做的是阻止客户端大小阻塞服务器,反之亦然。解决方案是使用计时器或超时。

  • 在服务器端,使用计时器检测发送(完整)图像文件所花费的时间过长。
  • 在客户端,使用计时器检测decoderStream花费的时间过长。
  • 在这两种情况下,您的代码应该能够调用关闭流。在客户端,decoderStream调用应该返回null。(至少,这就是文档所暗示的。)

您解决这个问题的方法如下所示:

代码语言:javascript
运行
复制
byte[] numOfBytes = new byte[inputStream.available()];
inputStream.read(numOfBytes);
BitmapFactory.Options options = new BitmapFactory.Options();
options.setExpectedImageSize(numOfBytes);
Bitmap bmp = BitmapFactory.decodeStream(inputStream, null, options);

这种做法存在致命的缺陷。

  1. 在套接字输入流InputStream.available上调用,只有才能告诉您有多少数据可以在不阻塞的情况下读取。基本上,这是已经接收到客户端的内核TCP/IP缓冲区的数据。可能不会是整个画面。 基本上,调用InputStream.available很少是正确的。(海事组织,如果他们反对的话,那是个好主意.虽然我怀疑他们会这样做。)
  2. 因此,inputStream.read(numOfBytes)不会读取整个图像。
  3. 但是,在numOfBytes中,您不会做任何有用的事情。
  4. Options中没有设置“预期图像大小”的方法。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70861089

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档