Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何有效读取流上JPEG图像的大小_C#_Stream_Serial Port_Jpeg_Barcode Scanner - Fatal编程技术网

C# 如何有效读取流上JPEG图像的大小

C# 如何有效读取流上JPEG图像的大小,c#,stream,serial-port,jpeg,barcode-scanner,C#,Stream,Serial Port,Jpeg,Barcode Scanner,我正在为我们的商业应用程序编写一个小插件,目标是使用条形码阅读器拍照 一切都正常,但问题是条形码阅读器每隔一段时间发送一次图片,它们是非常随机的,这取决于图像的大小和波特率。如果没有对我收到的字节进行全面分析,就无法判断图片是否已经加载 此时,我的逻辑试图通过分别搜索FF D8和FF D9字节来查找JPEG的开始/结束。问题是FFD9字节可能出现在映像内部 显然,我可以对字节进行一些特定的分析,但由于条形码阅读器不断发送数据,在接收字节时执行耗时的调试、CPU、IO等操作,最终会出现在蓝屏上 我

我正在为我们的商业应用程序编写一个小插件,目标是使用条形码阅读器拍照

一切都正常,但问题是条形码阅读器每隔一段时间发送一次图片,它们是非常随机的,这取决于图像的大小和波特率。如果没有对我收到的字节进行全面分析,就无法判断图片是否已经加载

此时,我的逻辑试图通过分别搜索FF D8和FF D9字节来查找JPEG的开始/结束。问题是FFD9字节可能出现在映像内部

显然,我可以对字节进行一些特定的分析,但由于条形码阅读器不断发送数据,在接收字节时执行耗时的调试、CPU、IO等操作,最终会出现在蓝屏上

我真正想要的是

我无法读取显示图像大小的字节 甚至研究大小是否会采用页眉本身/页脚 考虑到它本身。。。我得计算一下吗

检查我是否收到了所有字节

我将把我接收和处理字节的代码放在datareceived事件上,serialPortish和一个正确的完整映像(以字节为单位)和一个损坏的映像可能会有所帮助

数据接收设备

全速前进

损坏的字节数组

解决方案1


我可以很容易地做一个计时器,在首次调用DataReceived事件后等待500ms-2000ms。这将确保我拥有所有东西,然后我可以随心所欲地解析它。但显然,我不想总是无理地等待。

我想有人已经回答了这个问题:

我说得再好不过了

由于您将接收数据块,因此需要边走边解析。类似下面的内容。这是未经测试,我可能有计数计算向后大与小endian。它还假设一个区块可能跨越2个图像,或者区块可能拆分FFxx代码和计数。它也没有以任何方式进行优化,但对于小图像可能还可以

    private List<byte> imageBuffer = new List<byte>();
    private int imageState = 0;
    private int skipBytes = 0;

    private void ScannerPort_DataReceived(object sender, DataReceivedEventArgs e)
    {
        List<byte> tempBuffer = new List<byte>(e.RawBuffer);

        foreach (byte b in tempBuffer)
        {
            _ImageReceiving = true;
            imageBuffer.Add(b);

            switch (imageState)
            {
                case 0: // Searching for FF
                    if(b == 0xFF)
                        imageState = 1;
                    break;
                case 1: // First byte after FF
                    if (b == 0 || b == 1 || (b <= 0xD8 && b >= 0xD1))
                    {
                        // Code is not followed by a count
                        imageState = 0;
                    }
                    else if (b == 0xD9)
                    {
                        // End of image
                        _ImageReceiving = false;
                        this.OnImageReceived(imageBuffer.ToArray());
                        imageBuffer = new List<byte>();
                        imageState = 0;
                    }
                    else
                    {
                        // Code is 
                        imageState = 2;
                    }

                    break;
                case 2: // First count byte,  big endian?
                    skipBytes = ((int) b) * 0x100;
                    imageState = 3;
                    break;
                case 3: // Second count byte
                    skipBytes += b;
                    imageState = 4;
                    break;
                case 4: // skip
                    skipBytes--;
                    if (skipBytes == 0) imageState = 0;
                    break;
            }
        }
    }

我还没有测试过这个,我不知道它是否正确。但这就是我解决问题的方法。与其他答案相比,我试图解决一些问题

将字节数组保持为字节数组 单个读取事件可能包含来自多个图像的部分块 在内存流中组装整个图像 使用区块长度信息复制或跳过整个区块 如果内存缓冲区超过最大大小,您可能还希望将状态设置回0并停止复制图像。或者,如果在最后一个标头之后没有遇到新标头

私有内存流映像=新内存流; 私有int状态=0; 私有布尔拷贝=假; 私有int blockLen=-1; 私有void图像接收流图像{ //TODO使用整个图像缓冲区 } 私有无效接收字节[]块 { var i=0; 而我是0 { 剩余var=块长度-i; 如果剩余>blockLen 剩余=blockLen; 如果复制 image.Writeblock,i,剩余; i+=剩余; blockLen-=剩余;
如果blockLen我可能需要解释其中的循环,我们的条形码扫描仪会在图片制作完成后发送一个确认图片将被发送。它有17个字节长。这是删除循环。但这与图片本身无关…也许这里的答案会有所帮助:例如,似乎一些扫描仪供应商有API和l库,但您是否可能正在使用这样的供应商?为什么需要_WaitingForImageGuard?这可能会忽略下一个事件处理程序调用,并且会丢失下一个接收到的缓冲区。它可能包含一些有用的数据。查看生产者-消费者编程模式实现,这可能有助于理解如何正确地实现它例如,使用BlockingCollection接收到的缓冲区。条形码扫描器是保证一次发送整个图像还是可以将图像分割成多个部分?您必须将这些部分合并到一个数组中。@aepot我已将代码缩减到只处理重要内容的位置,通常那里有一个条形码序列,开关被打开由于我必须手动将扫描仪设置为图像模式,扫描仪无法读取其他信息。而WaitingForImage只有在收到完整图像时才会设置为False,并且没有其他方式。因此,在这个问题上它实际上没有任何作用。我通读了这篇文章,但问题只是开始了。如果我可以e立即接收完整图像。并对其进行解析。这里甚至没有问题。这是因为条形码阅读器在随机间隔中发送字节,在随机间隔中发送字节。并且,除了字节x=y之外,进行任何大的解析都会花费太长的时间来处理,而且扫描器将
发送数据时出现问题我知道具体原因这只是一个快速解释我需要一种方法,在运行时,没有任何循环可以知道整个过程何时完成……考虑到jpg的结构和数据可能被分割成任意块的要求,甚至可能分割标记或计数,我不确定如何在没有任何循环的情况下处理长度未知的缓冲区。我已经用一个可能的解决方案更新了答案,尽管还没有经过优化和测试。1不要在列表中添加字节数组。2不要逐个计算跳过的字节数。3.将图像块组装成内存流或其他东西。仍然不是好的解决方案。OP显然会在数据流中执行模式匹配,所以在出现错误的情况下,您应该在第一个字节馈送到您保存队列的自动机后尝试另一个字节,从autotamata中的第一个字节开始,直到潜在匹配的结束。如果不这样做,您将丢失结果-FF D8 FF D8
    private List<byte> imageBuffer = new List<byte>();
    private int imageState = 0;
    private int skipBytes = 0;

    private void ScannerPort_DataReceived(object sender, DataReceivedEventArgs e)
    {
        List<byte> tempBuffer = new List<byte>(e.RawBuffer);

        foreach (byte b in tempBuffer)
        {
            _ImageReceiving = true;
            imageBuffer.Add(b);

            switch (imageState)
            {
                case 0: // Searching for FF
                    if(b == 0xFF)
                        imageState = 1;
                    break;
                case 1: // First byte after FF
                    if (b == 0 || b == 1 || (b <= 0xD8 && b >= 0xD1))
                    {
                        // Code is not followed by a count
                        imageState = 0;
                    }
                    else if (b == 0xD9)
                    {
                        // End of image
                        _ImageReceiving = false;
                        this.OnImageReceived(imageBuffer.ToArray());
                        imageBuffer = new List<byte>();
                        imageState = 0;
                    }
                    else
                    {
                        // Code is 
                        imageState = 2;
                    }

                    break;
                case 2: // First count byte,  big endian?
                    skipBytes = ((int) b) * 0x100;
                    imageState = 3;
                    break;
                case 3: // Second count byte
                    skipBytes += b;
                    imageState = 4;
                    break;
                case 4: // skip
                    skipBytes--;
                    if (skipBytes == 0) imageState = 0;
                    break;
            }
        }
    }