mirror of
https://github.com/elima/gpu-playground.git
synced 2025-06-06 23:46:17 +00:00
140 lines
3.3 KiB
C
140 lines
3.3 KiB
C
#include <assert.h>
|
|
#include <errno.h>
|
|
#include "jpeg.h"
|
|
#include <string.h>
|
|
|
|
static void
|
|
handle_error_exit (j_common_ptr cinfo)
|
|
{
|
|
struct jpeg_error_handler *err_handler =
|
|
(struct jpeg_error_handler *) cinfo->err;
|
|
|
|
/* Display the message. */
|
|
(*cinfo->err->output_message) (cinfo);
|
|
|
|
err_handler->ctx->status = JPEG_STATUS_ERROR;
|
|
|
|
longjmp (err_handler->setjmp_buffer, 1);
|
|
}
|
|
|
|
/* public API */
|
|
|
|
bool
|
|
jpeg_decoder_init_from_filename (struct jpeg_ctx *self,
|
|
const char *filename)
|
|
{
|
|
assert (self != NULL);
|
|
assert (filename != NULL);
|
|
|
|
memset (self, 0x00, sizeof (struct jpeg_ctx));
|
|
|
|
self->file_obj = fopen (filename, "rb");
|
|
if (self->file_obj == NULL)
|
|
return false;
|
|
|
|
/* Set an error manager. */
|
|
self->cinfo.err =
|
|
jpeg_std_error (&self->err_handler.jpeg_error_mgr);
|
|
self->err_handler.jpeg_error_mgr.error_exit =
|
|
handle_error_exit;
|
|
|
|
self->err_handler.ctx = self;
|
|
|
|
if (setjmp (self->err_handler.setjmp_buffer) != 0) {
|
|
/* @FIXME: check the error code and fill errno accordingly */
|
|
jpeg_clear (self);
|
|
return false;
|
|
}
|
|
|
|
/* Create and set up the decompression object. */
|
|
jpeg_create_decompress (&self->cinfo);
|
|
jpeg_stdio_src (&self->cinfo, self->file_obj);
|
|
|
|
/* Read JPEG header. */
|
|
int result = jpeg_read_header (&self->cinfo, true);
|
|
if (result != JPEG_HEADER_OK) {
|
|
jpeg_clear (self);
|
|
return false;
|
|
}
|
|
|
|
jpeg_start_decompress (&self->cinfo);
|
|
|
|
self->row_stride = self->cinfo.output_width * self->cinfo.output_components;
|
|
self->width = self->cinfo.output_width;
|
|
self->height = self->cinfo.output_height;
|
|
self->format = self->cinfo.out_color_space;
|
|
|
|
self->status = JPEG_STATUS_DECODE_READY;
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
jpeg_clear (struct jpeg_ctx *self)
|
|
{
|
|
if (self->file_obj != NULL) {
|
|
fclose (self->file_obj);
|
|
self->file_obj = NULL;
|
|
}
|
|
|
|
if (self->status != JPEG_STATUS_NONE)
|
|
jpeg_destroy_decompress (&self->cinfo);
|
|
|
|
self->status = JPEG_STATUS_NONE;
|
|
}
|
|
|
|
ssize_t
|
|
jpeg_read (struct jpeg_ctx *self,
|
|
void *buffer,
|
|
size_t size,
|
|
size_t *first_row,
|
|
size_t *num_rows)
|
|
{
|
|
assert (self != NULL);
|
|
assert (self->status == JPEG_STATUS_DECODE_READY ||
|
|
self->status == JPEG_STATUS_DONE);
|
|
assert (size == 0 || buffer != NULL);
|
|
assert (self->row_stride > 0 && size >= self->row_stride);
|
|
|
|
size_t _num_rows = 0;
|
|
size_t _first_row = 0;
|
|
size_t result = 0;
|
|
|
|
if (self->status == JPEG_STATUS_DONE)
|
|
goto out;
|
|
|
|
_first_row = self->cinfo.output_scanline;
|
|
|
|
uint32_t lines = size / self->row_stride;
|
|
for (int32_t i = 0; i < lines; i++) {
|
|
uint8_t *rowptr[1];
|
|
rowptr[0] = buffer + self->row_stride * i;
|
|
|
|
jpeg_read_scanlines (&self->cinfo, rowptr, 1);
|
|
if (self->status == JPEG_STATUS_ERROR) {
|
|
/* @FIXME: handle exit errors here */
|
|
return -1;
|
|
}
|
|
|
|
_num_rows++;
|
|
}
|
|
|
|
_num_rows = self->cinfo.output_scanline - _first_row;
|
|
|
|
if (self->cinfo.output_scanline == self->cinfo.output_height) {
|
|
jpeg_finish_decompress (&self->cinfo);
|
|
self->status = JPEG_STATUS_DONE;
|
|
}
|
|
|
|
result = _num_rows * self->row_stride;
|
|
|
|
out:
|
|
if (first_row != NULL)
|
|
*first_row = _first_row;
|
|
|
|
if (num_rows != NULL)
|
|
*num_rows = _num_rows;
|
|
|
|
return result;
|
|
}
|