API TurboJPEG из libjpeg-turbo-1.5.1-vc.exe выдает неправильный вывод
Я написал тестовую программу на C в Visual Studio 2015 для тестирования libjpeg-turbo TurboJPEG-API.
В этой тестовой программе я создаю изображение размером 800x800 пикселей RGB и записываю его на диск. Когда я использую TJSAMP_GRAY
на tjCompress2
Функция создаваемого образа на диске выглядит хорошо:
Когда я использую TJSAMP_444
вместо этого изображение выглядит усталым:
Однако оба изображения не могут быть открыты в Adobe Photoshop, но в MS-Paint, Chrome или Internet Explorer. Все другие варианты, кроме TJSAMP_GRAY
в результате получается потертое изображение, а также настройка качества 100 с TJSAMP_GRAY
приводит к взвешенной продукции. (Изображения в этом посте копируются через скриншот и сохраняются как png для небольших данных.) Я также написал C#-программу, используя turbojpeg.dll
библиотека через P-Invoke. Эта программа производит корректный вывод.
Вопрос: где моя вина?
Исходный код в вопросе:
#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
Линия отсутствует _O_BINARY
, Таким образом, нет ошибки в конфигурации проекта или libjpeg-turbo TurboJPEG-API. Просто вывод записи на диск был интерпретирован как закодированный текст и поэтому был изменен _write
-функция или какой-то нижележащий экземпляр.
Правильный исходный код будет:
#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;
}