I’m trying to wrap this c example of libturbojpeg compression, but while tjCompress2()
doesn’t error, its supposed to write into jpegBuf
and set jpegSize
to the length of jpegBuf
but currently both are unchanged. It seems like tjCompress2()
isn’t being passed the srcBuf
properly, or jpegBuf
isn’t initialized properly…
I’m following the docs here: libjpeg.turbojpeg source code
C example (from here):
#include "turbojpeg.h"
#include <iostream>
#include <string.h>
#include <errno.h>
using namespace std;
int main(void)
{
unsigned char *srcBuf; //passed in as a param containing pixel data in RGB pixel interleaved format
tjhandle handle = tjInitCompress();
if(handle == NULL)
{
const char *err = (const char *) tjGetErrorStr();
cerr << "TJ Error: " << err << " UNABLE TO INIT TJ Compressor Object\n";
return -1;
}
int jpegQual =92;
int width = 128;
int height = 128;
int nbands = 3;
int flags = 0;
unsigned char* jpegBuf = NULL;
int pitch = width * nbands;
int pixelFormat = TJPF_GRAY;
int jpegSubsamp = TJSAMP_GRAY;
if(nbands == 3)
{
pixelFormat = TJPF_RGB;
jpegSubsamp = TJSAMP_411;
}
unsigned long jpegSize = 0;
srcBuf = new unsigned char[width * height * nbands];
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
srcBuf[(j * width + i) * nbands + 0] = (i) % 256;
srcBuf[(j * width + i) * nbands + 1] = (j) % 256;
srcBuf[(j * width + i) * nbands + 2] = (j + i) % 256;
}
}
int tj_stat = tjCompress2( handle, srcBuf, width, pitch, height,
pixelFormat, &(jpegBuf), &jpegSize, jpegSubsamp, jpegQual, flags);
if(tj_stat != 0)
{
const char *err = (const char *) tjGetErrorStr();
cerr << "TurboJPEG Error: " << err << " UNABLE TO COMPRESS JPEG IMAGE\n";
tjDestroy(handle);
handle = NULL;
return -1;
}
FILE *file = fopen("out.jpg", "wb");
if (!file) {
cerr << "Could not open JPEG file: " << strerror(errno);
return -1;
}
if (fwrite(jpegBuf, jpegSize, 1, file) < 1) {
cerr << "Could not write JPEG file: " << strerror(errno);
return -1;
}
fclose(file);
//write out the compress date to the image file
//cleanup
int tjstat = tjDestroy(handle); //should deallocate data buffer
handle = 0;
}
Julia attempt (with a simpler source image), using a Clang-generated wrapper (src here) :
using JpegTurbo_jll
libjpeg_wrap_dir = joinpath(@__DIR__, "..", "..", "gen", "libturbojpeg")
using CEnum
include(joinpath(libjpeg_wrap_dir, "ctypes.jl"))
export Ctm, Ctime_t, Cclock_t
include(joinpath(libjpeg_wrap_dir, "libturbojpeg_common.jl"))
include(joinpath(libjpeg_wrap_dir, "libturbojpeg_api.jl"))
using ColorTypes, ImageCore, FixedPointNumbers
img = rand(RGB{N0f8}, 10, 10)
rawimg = rawview(channelview(img))
srcBuf = collect(vec(rawimg))
nbands, width, height = size(rawimg)
pitch = Int(width * nbands)
pixelFormat = nbands == 3 ? TJPF_RGB : TJPF_GRAY
jpegSubsamp = nbands == 3 ? TJSAMP_411 : TJSAMP_GRAY
jpegQual = 92
flags = 0
handle = tjInitCompress()
handle == C_NULL && error("TurboJPEG Error: Unable to initialize compressor object: $(unsafe_string(tjGetErrorStr()))")
jpegBuf = Ptr{UInt8}(C_NULL)
jpegSize = Culong(0)
tj_stat = tjCompress2(handle, srcBuf, width, pitch, height, pixelFormat,
Ref(jpegBuf), Ref(jpegSize), jpegSubsamp, jpegQual, flags)
if tj_stat != 0
err = tjGetErrorStr()
tjDestroy(handle)
handle = C_NULL
error("TurboJPEG Error: $(unsafe_string(err))")
end
@show jpegSize
jpegBuf_j = unsafe_wrap(Array, jpegBuf, jpegSize; own = false)
open(joinpath(@__DIR__, "out.jpg"), "w") do io
write(io, jpegBuf_j)
end
tjstat = tjDestroy(handle) #should deallocate data buffer
handle = nothing
tjFree(jpegBuf)
The @show jpegSize
returns 0x0000000000000000
, indicating that tjCompress2()
hasn’t errored, but that no data has been written to jpegBuf