来自 libjpeg-turbo-1.5.1-vc.exe 的 TurboJPEG API 产生错误的输出

Posted

技术标签:

【中文标题】来自 libjpeg-turbo-1.5.1-vc.exe 的 TurboJPEG API 产生错误的输出【英文标题】:TurboJPEG API from libjpeg-turbo-1.5.1-vc.exe produces wrong output 【发布时间】:2016-10-10 02:15:21 【问题描述】:

我在 Visual Studio 2015 中用 C 语言编写了一个测试程序,用于测试 libjpeg-turbo TurboJPEG-API。

在这个测试程序中,我生成一个 800x800 RGB 像素的图像并将其写入磁盘。当我在tjCompress2 函数中使用TJSAMP_GRAY 时,磁盘上生成的图像看起来不错:

当我使用TJSAMP_444 时,图像看起来很奇怪:

但是,这两个图像都无法在 Adob​​e Photoshop 中打开,而是在 MS-Paint、Chrome 或 Internet Explorer 中打开。除了TJSAMP_GRAY 之外的所有其他选项都会产生奇怪的图像,TJSAMP_GRAY 的质量设置为 100 也会产生奇怪的输出。 (这篇文章中的图片是通过屏幕截图复制的,并保存为 png 以用于较小的数据。) 我还通过 P-Invoke 使用 turbojpeg.dll 库编写了一个 C#-Program。该程序正在产生有效的输出。

问题:我的错在哪里?

有问题的源代码:

#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "turbojpeg.h"

unsigned char buffer[800 * 800 * 3];

int main(int argc, char** argv)

    unsigned long size = 0;

    unsigned char* compressedImage = NULL;

    for (int x = 0; x < 800; x++)
        for (int y = 0; y < 800; y++)
        
            switch ((x / 80) % 3)
            
            case 0:
                buffer[(y * 800 + x) * 3] = 255;
                buffer[(y * 800 + x) * 3 + 1] = 0;
                buffer[(y * 800 + x) * 3 + 2] = 0;
                break;
            case 1:
                buffer[(y * 800 + x) * 3] = 0;
                buffer[(y * 800 + x) * 3 + 1] = 255;
                buffer[(y * 800 + x) * 3 + 2] = 0;
                break;
            case 2:
                buffer[(y * 800 + x) * 3] = 0;
                buffer[(y * 800 + x) * 3 + 1] = 0;
                buffer[(y * 800 + x) * 3 + 2] = 255;
                break;
            
        

    tjhandle compressor = tjInitCompress();

    compressedImage = tjAlloc(1024 * 1024 * 4);

    size = 1024 * 1024 * 4;

    tjCompress2(compressor, buffer, 800, 0, 800, TJPF_RGB, &compressedImage, &size, TJSAMP_444, 80, TJFLAG_NOREALLOC | TJFLAG_ACCURATEDCT);

    tjDestroy(compressor);

    int handle = _wopen(L"D:\\file.jpeg", _O_CREAT | _O_WRONLY | _O_TRUNC, _S_IREAD | _S_IWRITE);

    printf("LENGTH=%ld\n", size);

    if (_write(handle, compressedImage, size) != size)
        printf("Write Error.\n");

    _close(handle);

    tjFree(compressedImage);

    return 0;

为了完整,测试 C# 源代码,它工作正常:

class Program

    [DllImport("turbojpeg", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr tjInitCompress();

    [DllImport("turbojpeg", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr tjAlloc(int bytes);

    [DllImport("turbojpeg", CallingConvention = CallingConvention.Cdecl)]
    private static extern int tjCompress2(IntPtr handle, IntPtr srcBuf, int width, int pitch, int height, int pixelFormat, ref IntPtr jpegBuf, ref ulong jpegSize, int jpegSubsamp, int jpegQual, int flags);

    [DllImport("turbojpeg", CallingConvention = CallingConvention.Cdecl)]
    private static extern int tjDestroy(IntPtr handle);

    [DllImport("turbojpeg", CallingConvention = CallingConvention.Cdecl)]
    private static extern void tjFree(IntPtr buffer);

    static void Main(string[] args)
    
        ulong size = 1024 * 1024 * 4;

        byte[] buffer = new byte[800 * 800 * 3];

        for (int x = 0; x < 800; x++)
            for (int y = 0; y < 800; y++)
            
                switch ((x / 80) % 3)
                
                    case 0:
                        buffer[(y * 800 + x) * 3] = 255;
                        buffer[(y * 800 + x) * 3 + 1] = 0;
                        buffer[(y * 800 + x) * 3 + 2] = 0;
                        break;
                    case 1:
                        buffer[(y * 800 + x) * 3] = 0;
                        buffer[(y * 800 + x) * 3 + 1] = 255;
                        buffer[(y * 800 + x) * 3 + 2] = 0;
                        break;
                    case 2:
                        buffer[(y * 800 + x) * 3] = 0;
                        buffer[(y * 800 + x) * 3 + 1] = 0;
                        buffer[(y * 800 + x) * 3 + 2] = 255;
                        break;
                
            

        IntPtr umBuffer = Marshal.AllocHGlobal(800 * 800 * 3);
        Marshal.Copy(buffer, 0, umBuffer, 800 * 800 * 3);

        IntPtr compressor = tjInitCompress();

        IntPtr compressedImage = tjAlloc(1024 * 1024 * 4);

        tjCompress2(compressor, umBuffer, 800, 0, 800, 0, ref compressedImage, ref size, 0, 80, 5 * 1024);

        byte[] mCPData = new byte[size];

        Marshal.Copy(compressedImage, mCPData, 0, (int)size);

        System.IO.File.WriteAllBytes("D:\\managed.jpeg", mCPData);

        tjFree(compressedImage);

        Marshal.FreeHGlobal(umBuffer);
    

【问题讨论】:

【参考方案1】:

_wopen-Line 缺少_O_BINARY。因此,项目配置或 libjpeg-turbo TurboJPEG-API 中没有错误。只是,写入磁盘的输出被解释为编码文本,因此被_write-function 或一些底层实例修改。

正确的源代码是:

#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "turbojpeg.h"

unsigned char buffer[800 * 800 * 3];

int main(int argc, char** argv)

    unsigned long size = 0;

    unsigned char* compressedImage = NULL;

    for (int x = 0; x < 800; x++)
        for (int y = 0; y < 800; y++)
        
            switch ((x / 80) % 3)
            
            case 0:
                buffer[(y * 800 + x) * 3] = 255;
                buffer[(y * 800 + x) * 3 + 1] = 0;
                buffer[(y * 800 + x) * 3 + 2] = 0;
                break;
            case 1:
                buffer[(y * 800 + x) * 3] = 0;
                buffer[(y * 800 + x) * 3 + 1] = 255;
                buffer[(y * 800 + x) * 3 + 2] = 0;
                break;
            case 2:
                buffer[(y * 800 + x) * 3] = 0;
                buffer[(y * 800 + x) * 3 + 1] = 0;
                buffer[(y * 800 + x) * 3 + 2] = 255;
                break;
            
        

    tjhandle compressor = tjInitCompress();

    compressedImage = tjAlloc(1024 * 1024 * 4);

    size = 1024 * 1024 * 4;

    tjCompress2(compressor, buffer, 800, 0, 800, TJPF_RGB, &compressedImage, &size, TJSAMP_444, 80, TJFLAG_NOREALLOC | TJFLAG_ACCURATEDCT);

    tjDestroy(compressor);

    int handle = _wopen(L"D:\\file.jpeg", _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY, _S_IREAD | _S_IWRITE);

    printf("LENGTH=%ld\n", size);

    if (_write(handle, compressedImage, size) != size)
        printf("Write Error.\n");

    _close(handle);

    tjFree(compressedImage);

    return 0;

【讨论】:

以上是关于来自 libjpeg-turbo-1.5.1-vc.exe 的 TurboJPEG API 产生错误的输出的主要内容,如果未能解决你的问题,请参考以下文章

书评:男人来自火星,女人来自金星-约翰.格雷

为啥 WCF 服务能够处理来自不同进程的调用而不是来自线程的调用

来自 viewDidAppear 的 Segue 调用有效,但不是来自 viewWillAppear

求职作业帮 C++方向面经

来自 CWnd 的 ReleaseDC 覆盖来自 winuser 的 ReleaseDC

来自麦克风的声音与来自扬声器的声音