Skip to content
Open
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,17 @@ if(HAIO_TEST)
include(CTest)
set(tests
"test_get_format_from_extension,src/Common_String/get_format_from_ext.c"
"test_get_format_from_magic,src/Common_String/get_format_from_magic.c"
"test_get_codec_workers_from_formats,src/Backend_Workers/codecs.c"
"test_convert_tokenize_args,src/Frontend_Convert/tokenize.c,src/Frontend_Convert/format.c,src/Common_String/get_ext_from_str.c,src/Common_String/get_format_from_ext.c,src/Common_String/get_format_from_magic.c"
)
foreach(deps IN LISTS tests)
string(REPLACE "," ";${CMAKE_SOURCE_DIR}/" deps "${deps}")
list(GET deps 0 tests_name)
list(REMOVE_AT deps 0)
add_executable("${tests_name}" "${CMAKE_SOURCE_DIR}/tests/${tests_name}.c;${deps}")
target_include_directories(${tests_name} PRIVATE "${CMAKE_SOURCE_DIR}/include;${CMAKE_BINARY_DIR}/include")
add_dependencies(${tests_name} haio_functions haio_codec_paths)
add_test(NAME "${tests_name}" COMMAND "${tests_name}")
endforeach()
endif()
48 changes: 43 additions & 5 deletions src/Backend_Workers/pipeline.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,68 @@ void PipelineBegin(haio_pipeline_t* pipe, haio_type_t first_step) {
* @details add tasks to streaming pipeline
* @param [in,out] pipe
*/
void PipelineStepAdd(haio_pipeline_t* pipe, haio_type_t next_step) {
int PipelineStepAdd(haio_pipeline_t* pipe, haio_type_t next_step) {
static char path_not_found[] = "pipeline path not found";
static char worker_limit_exceeded[] = "pipeline worker limit exceeded";
haio_worker_func_t workers[HAIO_MAX_STEPS_BY_WORKER];
haio_type_t from = pipe->current_format;
haio_type_t to = next_step;
haio_type_t result = HAIO_TYPE_NULL;

uint8_t nworkers = GetCodecWorkersFromFormats(from, to, workers, HAIO_MAX_STEPS_BY_WORKER, &result);
uint8_t nworkers;

if (PipelineHasError(pipe)) {
return 1;
}

nworkers = GetCodecWorkersFromFormats(
from,
to,
workers,
HAIO_MAX_STEPS_BY_WORKER,
&result
);

if (!nworkers || result == HAIO_TYPE_NULL) {
pipe->error = path_not_found;
return 1;
}

if (nworkers > HAIO_MAX_WORKERS_BY_PIPE - pipe->worker_count) {
pipe->error = worker_limit_exceeded;
return 1;
}

pipe->current_format = result;
pipe->state = HAIO_FSM_PIPE_PREPARE;

memcpy(&pipe->workers[pipe->worker_count], workers, nworkers * sizeof(haio_worker_func_t));
memcpy(
&pipe->workers[pipe->worker_count],
workers,
nworkers * sizeof(haio_worker_func_t)
);

pipe->worker_count += nworkers;

return 0;
}

/**
* @details finish pipeline tasks
* @param [in,out] pipe
*/
void PipelineEnd(haio_pipeline_t* pipe, haio_type_t last_step) {
PipelineStepAdd(pipe, last_step);
int PipelineEnd(haio_pipeline_t* pipe, haio_type_t last_step) {
if (PipelineStepAdd(pipe, last_step)) {
return 1;
}

pipe->state = HAIO_FSM_PIPE_RUNNING;

for (uint8_t i = 1; i < pipe->worker_count; i++) {
pipe->handlers[i].canvas.parent = &pipe->handlers[i - 1].canvas;
}

return 0;
}

/**
Expand Down
18 changes: 18 additions & 0 deletions src/Common_String/get_format_from_magic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <stddef.h>
#include <string.h>

#include "haio.h"

haio_type_t GetFormatFromMagic(const unsigned char *buffer, size_t len)
{
static const unsigned char png_signature[] = {
0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'
};

if (len >= sizeof(png_signature) &&
memcmp(buffer, png_signature, sizeof(png_signature)) == 0) {
return HAIO_TYPE_IMG_PNG;
}

return HAIO_TYPE_NULL;
}
193 changes: 167 additions & 26 deletions src/Frontend_Convert/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,182 @@

#include "haio.h"
#include "haio/functions.h"
#include "convert.h"

#define BUFFER_SIZE 1024
#define BUFFER_SIZE 4096

int FrontendConvertCli(int argc, char* argv[]) {
if (argc <= 2) {
printf("usage:\n./img convert input.png output.ppm\n");
return 1;
static void PrintConvertUsage(void)
{
printf("usage:\n");
printf("haio convert input.png [options] output.ppm\n");
printf("haio convert png:- output.ppm\n");
printf("\n");
printf("options:\n");
printf(" -crop crop image using the default crop filter\n");
}

static void PrintConvertBuildError(convert_command_t *cmd, haio_pipeline_t *pipe)
{
if (cmd->error.message) {
convert_print_error(cmd->error);
return;
}

size_t nbytes;
char buffer[4096];
FILE* f_in = fopen(argv[1], "rb");
FILE* f_out = fopen(argv[2], "wb");
if (PipelineHasError(pipe)) {
printf("[error] %s\n", GetPipelineError(pipe));
}
}

haio_pipeline_t pipe;
PipelineBegin(&pipe, HAIO_TYPE_BUFFER);
PipelineStepAdd(&pipe, HAIO_TYPE_IMG_PNG);
//PipelineStepAdd(&pipe, HAIO_TYPE_FILTER_CROP);
PipelineEnd(&pipe, HAIO_TYPE_IMG_PPM);

while(PipelineIsRunning(&pipe)) {
nbytes = fread(buffer, sizeof(char), sizeof(buffer), f_in);
nbytes = PipelineProcess(&pipe, buffer, nbytes, buffer, sizeof(buffer));
fwrite(buffer, sizeof(char), nbytes, f_out);
static int OpenConvertInput(convert_command_t *cmd, FILE **f_in)
{
int err = 1;

do {
if (cmd->has_generator) {
*f_in = NULL;
err = 0;
break;
}

if (cmd->input_format_name && cmd->input_format == HAIO_TYPE_NULL) {
convert_print_unsupported_format("input", cmd->input_format_name, cmd->input_path);
break;
}

if (strcmp(cmd->input_path, "-") == 0) {
*f_in = stdin;
err = 0;
break;
}

*f_in = fopen(cmd->input_path, "rb");
if (!*f_in) {
printf("[error] could not open input: %s\n", cmd->input_path);
break;
}

if (!cmd->input_format_name) {
cmd->input_format = convert_input_format_from_file(*f_in, cmd->input_path);
}

if (cmd->input_format == HAIO_TYPE_NULL) {
convert_print_unsupported_format("input", cmd->input_format_name, cmd->input_path);
fclose(*f_in);
*f_in = NULL;
break;
}

err = 0;
}
while(0);

return err;
}

static int OpenConvertOutput(convert_command_t *cmd, FILE **f_out)
{
int err = 1;

if (PipelineHasError(&pipe)) {
printf("[error] %s", GetPipelineError(&pipe));
return 1;
do {
if (cmd->output_is_stdout) {
*f_out = stdout;
err = 0;
break;
}

*f_out = fopen(cmd->output_path, "wb");
if (!*f_out) {
printf("[error] could not open output: %s\n", cmd->output_path);
break;
}

err = 0;
}
while(0);

return err;
}

int FrontendConvertCli(int argc, char* argv[])
{
int err = 1;
int write_error = 0;
size_t nread;
size_t nwrite;
char buffer[BUFFER_SIZE];

//printf("feito!");
FILE* f_in = NULL;
FILE* f_out = NULL;

fclose(f_in);
fclose(f_out);
convert_command_t cmd;
haio_pipeline_t pipe;

do {
if (argc <= 2) {
PrintConvertUsage();
break;
}

if (convert_tokenize_args(&cmd, argc, argv)) {
convert_print_error(cmd.error);
break;
}

if (cmd.output_format == HAIO_TYPE_NULL) {
convert_print_unsupported_format("output", cmd.output_format_name, argv[argc - 1]);
break;
}

if (OpenConvertInput(&cmd, &f_in)) {
break;
}

if (convert_build_pipeline(&cmd, &pipe)) {
PrintConvertBuildError(&cmd, &pipe);
break;
}

if (OpenConvertOutput(&cmd, &f_out)) {
break;
}

while(PipelineIsRunning(&pipe)) {
nread = fread(buffer, sizeof(char), sizeof(buffer), f_in);

nwrite = PipelineProcess(&pipe, buffer, nread, buffer, sizeof(buffer));

if (nwrite && fwrite(buffer, sizeof(char), nwrite, f_out) != nwrite) {
printf("[error] could not write output: %s\n", cmd.output_path);
write_error = 1;
break;
}
}

Comment thread
guilhhotina marked this conversation as resolved.
if (write_error) {
break;
}

if (ferror(f_in)) {
printf("[error] could not read input: %s\n", cmd.input_path);
break;
}

if (PipelineHasError(&pipe)) {
printf("[error] %s\n", GetPipelineError(&pipe));
break;
}

err = 0;
}
while(0);

if (f_in && f_in != stdin) {
fclose(f_in);
}

if (f_out && f_out != stdout) {
fclose(f_out);
}

return 0;
return err;
}
59 changes: 59 additions & 0 deletions src/Frontend_Convert/convert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

#include "haio.h"

#define CONVERT_MAX_TOKENS 32
#define CONVERT_FORMAT_PROBE_SIZE 16

typedef enum {
CONVERT_TOKEN_INPUT_FILE,
CONVERT_TOKEN_OUTPUT_FILE,
CONVERT_TOKEN_GENERATOR_XC,
CONVERT_TOKEN_GENERATOR_GRADIENT,
CONVERT_TOKEN_FILTER_CROP,
CONVERT_TOKEN_FILTER_FX
} convert_token_type_t;

typedef struct {
convert_token_type_t type;
char *value;
char *arg;
haio_type_t format;
} convert_token_t;

typedef struct {
char *message;
char *token;
} convert_error_t;

typedef struct {
convert_error_t error;
uint8_t token_count;
bool has_input;
bool has_generator;
bool output_is_stdout;
char *input_path;
char *output_path;
char *input_format_name;
char *output_format_name;
haio_type_t input_format;
haio_type_t output_format;
convert_token_t tokens[CONVERT_MAX_TOKENS];
} convert_command_t;

haio_type_t convert_format_from_path(char *path);
haio_type_t convert_input_format_from_file(FILE *f_in, char *path);
void convert_print_unsupported_format(const char *kind, char *format_name, char *fallback);
int convert_tokenize_args(convert_command_t *cmd, int argc, char* argv[]);
int convert_build_pipeline(convert_command_t *cmd, haio_pipeline_t *pipe);
void convert_print_error(convert_error_t error);

bool convert_slice_iequals(char *txt, size_t len, const char *expected);
char *convert_find_format_separator(char *txt);
haio_type_t convert_format_from_name(char *name, size_t len);
bool convert_known_format_prefix(char *name, size_t len);
Loading