如何将十六进制字符串保存到 spiffs 中的 png 文件以创建图像

问题描述

我正在尝试通过 TCP/IP 连接从 node.js 服务器发送图像文件。我使用 fs.createReadStream 将图像文件转换为十六进制字符串,并在客户端按预期接收十六进制字符串。现在我需要弄清楚如何使用十六进制字符串在客户端重建图像。

Node.js 代码

function newStream(res,imageFile){
    var readStream = fs.createReadStream(imageFile);
    readStream.on('data',chunk => {
        res.send(chunk.toString('hex'));
    });
}

ESP32 开发板上用于将数据保存到 spiffs 中的 png 文件的客户端代码(C 语言):

#define MAX_HTTP_OUTPUT_BUFFER 512
int max_buff = 512;

static void http_native_request(void)
{
    char output_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
    int content_length = 0;
    int track_length = 0;

    esp_http_client_config_t config = {
        .url = "http://192.168.1.122/api?file=file01",};
    esp_http_client_handle_t client = esp_http_client_init(&config);

    // GET Request
    esp_http_client_set_method(client,HTTP_METHOD_GET);
    esp_err_t err = esp_http_client_open(client,0);
    if (err != ESP_OK) {
        ESP_LOGE(TAG,"Failed to open HTTP connection: %s",esp_err_to_name(err));
    } else {
        content_length = esp_http_client_fetch_headers(client);
        track_length = content_length;
        if (content_length < 0) {
            ESP_LOGE(TAG,"HTTP client fetch headers Failed");
        } else {
            do {
            int data_read = esp_http_client_read_response(client,output_buffer,max_buff);
            output_buffer[max_buff] = '\0';
            create_file_app(output_buffer); //saves output_buffer to a newly created png file
            if (data_read >= 0) {
                track_length -= data_read;
                if (max_buff > track_length){
                    max_buff = track_length;
                }
            } else {
                ESP_LOGE(TAG,"Failed to read response");
            }
            } while (
                track_length>0
            );
        }
    }
    esp_http_client_close(client);
}

来自服务器的十六进制字符串如下所示(具有 png 文件的签名):

89504e470d0a1a0a0000000d494844520000006400000064080600 ... f03b8c85cc0643044ae0000000049454e44ae426082

我的研究表明我需要在客户端将此十六进制字符串转换为二进制数据。但是当我这样做时(此处未显示转换代码),由 create_file_app 函数创建的 png 文件显示客户端接收到的二进制字符串(正确对应于十六进制字符串),而不是显示我认为我下载的图像服务器。如何保存此十六进制数据,以便在打开在客户端创建的 png 文件时获得预期的图像?或者有没有可以帮助解决这个问题的 C 库?

编辑 1:

我从 node.js 服务器按原样发送图像数据的代码,无需转换为十六进制或其他格式:

function newStream(res,chunk => {
        res.send(chunk);
    });
}

以下是 node.js 控制台为“块”显示内容

<Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 64 00 00 00 64 08 06 00 00 00 70 e2 95 54 00 00 00 06 62 4b 47 44 00 ff 00 ff 00 ff a0 bd a7 ... >

在客户端,这里是 ESP 的 esp_http_client_read_response() 代码

int esp_http_client_read_response(esp_http_client_handle_t client,char *buffer,int len)
{
    int read_len = 0;
    while (read_len < len) {
        int data_read = esp_http_client_read(client,buffer + read_len,len - read_len);
        if (data_read <= 0) {
            return read_len;
        }
        read_len += data_read;
    }
    return read_len;
}

Esp_http_client_read_response 调用 esp_http_client_read(同样,这是由 ESP 发布的) - 这是它的代码

int esp_http_client_read(esp_http_client_handle_t client,int len)
{
    esp_http_buffer_t *res_buffer = client->response->buffer;

    int rlen = ESP_FAIL,ridx = 0;
    if (res_buffer->raw_len) {
        int remain_len = client->response->buffer->raw_len;
        if (remain_len > len) {
            remain_len = len;
        }
        memcpy(buffer,res_buffer->raw_data,remain_len);
        res_buffer->raw_len -= remain_len;
        res_buffer->raw_data += remain_len;
        ridx = remain_len;
    }
    int need_read = len - ridx;
    bool is_data_remain = true;
    while (need_read > 0 && is_data_remain) {
        if (client->response->is_chunked) {
            is_data_remain = !client->is_chunk_complete;
        } else {
            is_data_remain = client->response->data_process < client->response->content_length;
        }

        if (!is_data_remain) {
            break;
        }
        int byte_to_read = need_read;
        if (byte_to_read > client->buffer_size_rx) {
            byte_to_read = client->buffer_size_rx;
        }
        errno = 0;
        rlen = esp_transport_read(client->transport,res_buffer->data,byte_to_read,client->timeout_ms);
        ESP_LOGD(TAG,"need_read=%d,byte_to_read=%d,rlen=%d,ridx=%d",need_read,rlen,ridx);

        if (rlen <= 0) {
            if (errno != 0) {
                esp_log_level_t sev = ESP_LOG_WARN;
                /* On connection close from server,recv should ideally return 0 but we have error conversion
                 * in `tcp_transport` SSL layer which translates it `-1` and hence below additional checks */
                if (rlen == -1 && errno == ENOTCONN && client->response->is_chunked) {
                    /* Explicit call to parser for invoking `message_complete` callback */
                    http_parser_execute(client->parser,client->parser_settings,0);
                    /* ...and lowering the message severity,as closed connection from server side is expected in chunked transport */
                    sev = ESP_LOG_DEBUG;
                }
                ESP_LOG_LEVEL(sev,TAG,"esp_transport_read returned:%d and errno:%d ",errno);
            }
            if (rlen < 0 && ridx == 0) {
                return ESP_FAIL;
            } else {
                return ridx;
            }
        }
        res_buffer->output_ptr = buffer + ridx;
        http_parser_execute(client->parser,rlen);
        ridx += res_buffer->raw_len;
        need_read -= res_buffer->raw_len;

        res_buffer->raw_len = 0; //clear
        res_buffer->output_ptr = NULL;
    }

    return ridx;
}

这是我的 create_file_app() 代码,它将检索到的数据保存在 spiffs 文件中:

void create_file_app(char *buffer)
{
    ESP_LOGI(TAG,"opening file");
    FILE* f = fopen("/spiffs/hello1.png","a+");
    if (f == NULL) {
        ESP_LOGE(TAG,"Failed to open file for writing");
        return;
    }
    fprintf(f,buffer);
    fclose(f);
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)