生成图片的base64编码(纯C语言实现)

2024-09-02 14:04

本文主要是介绍生成图片的base64编码(纯C语言实现),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

Base64编码是一种广泛使用的编码方案,将任意二进制数据转换为可打印的ASCII字符字符串。这种编码方式之所以重要,是因为许多通信协议和存储介质对数据的可传输性和可存储性有特定的要求,它们可能无法直接处理或有效传输二进制数据。Base64编码通过使用64个字符的标准字符集——包括大写字母A-Z、小写字母a-z、数字0-9以及符号“+”和“/”,来表示二进制数据中的每一个6位组。为了标识编码的结束,Base64还使用了=作为填充字符。

image-20240716143247390

在实际应用中,Base64编码常见于电子邮件附件、在URLs中嵌入二进制数据、在网页中内联图像和字体文件、以及在配置文件和数据库中存储非文本数据等多种场景。例如,在HTML或CSS文件中,可以使用Base64编码的图像数据直接作为背景图像,而无需额外的HTTP请求,这在某些情况下可以提高页面加载速度,尽管这样做可能会增加文件大小,因为Base64编码通常会使原始数据膨胀约33%左右。

在C语言中,Base64编码的实现主要涉及几个关键步骤:首先,输入的二进制数据被分成6位的区块;然后,每个6位区块被映射到Base64字符集中相应的字符;接下来,如果最后一个区块不足6位,使用0进行填充,并添加等于号作为填充字符以保持输出的长度一致。

编码过程可以分解为以下步骤:

  1. 将输入的二进制数据读入内存缓冲区。
  2. 遍历缓冲区,每次取出24位数据(即3个字节),这足以生成4个Base64字符。
  3. 将这24位分为4个6位组。
  4. 使用6位组索引Base64字符集,找到对应的字符并输出。
  5. 如果到达缓冲区末尾时剩余不足24位,使用0填充剩余位数,并输出相应的Base64字符,同时在输出字符串末尾添加等于号作为填充。

在C语言中实现Base64编码时,可以定义一个包含64个字符的数组,存储Base64字符集,通过循环和位操作来处理数据。由于C语言提供了对内存和位操作的直接访问,因此在性能敏感的应用中,使用C语言实现的Base64编码可以非常高效。

二、代码实操

2.1 将二进制数据转为Base64编码

下面是C语言程序示例,将给定的一串二进制数据转换成Base64编码并打印出来。程序使用了标准库函数,并且没有依赖任何外部库。程序中包含了创建Base64编码所需的所有步骤,如初始化字符集、读取输入数据、编码数据并打印结果。

#include <stdio.h>
#include <stdlib.h>#define BASE64_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#define CHUNK_SIZE 3
#define BASE64_CHUNK_SIZE 4void base64_encode(unsigned char const *bytes_to_encode, unsigned int in_len, char *out_text)
{unsigned char const *in = bytes_to_encode;unsigned char *out = (unsigned char*)out_text;unsigned int i;unsigned int j;unsigned int val;for (i = 0, j = 0; i < in_len - 2; i += CHUNK_SIZE, j += BASE64_CHUNK_SIZE) {val = ((in[i] & 0xFC) >> 2);out[j] = BASE64_CHARS[val];val = ((in[i] & 0x03) << 4) | ((in[i + 1] & 0xF0) >> 4);out[j + 1] = BASE64_CHARS[val];val = ((in[i + 1] & 0x0F) << 2) | ((in[i + 2] & 0xC0) >> 6);out[j + 2] = BASE64_CHARS[val];val = (in[i + 2] & 0x3F);out[j + 3] = BASE64_CHARS[val];}// Handle the last chunk gracefully.switch (in_len % CHUNK_SIZE) {case 1:out[j] = BASE64_CHARS[((in[i] & 0xFC) >> 2)];out[j + 1] = BASE64_CHARS[((in[i] & 0x03) << 4)];out[j + 2] = '=';out[j + 3] = '=';break;case 2:val = ((in[i] & 0xFC) >> 2);out[j] = BASE64_CHARS[val];val = ((in[i] & 0x03) << 4) | ((in[i + 1] & 0xF0) >> 4);out[j + 1] = BASE64_CHARS[val];out[j + 2] = BASE64_CHARS[((in[i + 1] & 0x0F) << 2)];out[j + 3] = '=';break;}
}int main()
{unsigned char data[] = {0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x27, 0x0b, 0xcf, 0xa3, 0x57, 0x67};unsigned int data_len = sizeof(data);char encoded_data[100]; // Assuming enough space for the encoded string.base64_encode(data, data_len, encoded_data);encoded_data[data_len * 4 / 3] = '\0'; // Null terminate the string.printf("Original data: ");for (int i = 0; i < data_len; i++) {printf("%02x ", data[i]);}printf("\n");printf("Encoded data: %s\n", encoded_data);return 0;
}

在例子中,data 数组包含了要被编码的数据。base64_encode 函数接受这些数据,并将其转换为Base64编码。编码后的字符串被存储在 encoded_data 数组中。注意,encoded_data 数组的大小应该足够容纳编码后的字符串,因为Base64编码后的字符串长度通常是原始数据长度的4/3倍。

这个程序将打印出原始数据和编码后的Base64字符串。可以根据需要修改 data 数组的内容,以便测试不同的输入。

image-20240716142913231

2.2 实现图片的base64编码和解码

下面是一个完整的C语言程序,实现了将图片文件编码为Base64字符串,并且可以将Base64字符串解码为图片并保存到本地磁盘。这个示例程序使用标准C库,不依赖于任何第三方库。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 函数:将二进制数据编码为Base64字符串
char* base64_encode(const unsigned char* src, size_t len) {static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";char* out, * pos;const unsigned char* end, * in;size_t olen;int line_len;olen = len * 4 / 3 + 4; // 输出长度olen += olen / 72; // 换行符olen++; // 结尾的NULL字符out = (char*)malloc(olen);if (out == NULL) return NULL;end = src + len;in = src;pos = out;line_len = 0;while (end - in >= 3) {*pos++ = base64_table[in[0] >> 2];*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];*pos++ = base64_table[in[2] & 0x3f];in += 3;if (line_len += 4, line_len == 72) {*pos++ = '\n';line_len = 0;}}if (end - in) {*pos++ = base64_table[in[0] >> 2];if (end - in == 1) {*pos++ = base64_table[(in[0] & 0x03) << 4];*pos++ = '=';}else {*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];*pos++ = base64_table[(in[1] & 0x0f) << 2];}*pos++ = '=';}*pos = '\0';return out;
}// 函数:将Base64字符串解码为二进制数据
unsigned char* base64_decode(const char* src, size_t* out_len) {static const unsigned char base64_table[] = {0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // +100xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff,  // +200xff, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,  // +300x3c, 0x3d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x3f,  // +400xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03,  // +500x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,  // +600x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,  // +700x18, 0x19, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // +800xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,  // +900x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,  // +1000x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33          // +110};unsigned char dtable[256], * out, * pos, block[4], tmp;size_t i, count, olen;int pad = 0;memset(dtable, 0x80, 256);for (i = 0; i < sizeof(base64_table); i++)dtable[base64_table[i]] = (unsigned char)i;dtable['='] = 0;count = 0;for (i = 0; i < strlen(src); i++) {if (dtable[src[i]] != 0x80)count++;}if (count == 0 || count % 4)return NULL;olen = count / 4 * 3;pos = out = (unsigned char*)malloc(olen);if (out == NULL) return NULL;for (i = 0; i < strlen(src); i++) {tmp = dtable[src[i]];if (tmp == 0x80) continue;if (src[i] == '=')pad++;block[count++] = tmp;if (count == 4) {*pos++ = (block[0] << 2) | (block[1] >> 4);*pos++ = (block[1] << 4) | (block[2] >> 2);*pos++ = (block[2] << 6) | block[3];count = 0;if (pad) {if (pad == 1) pos--;else if (pad == 2) pos -= 2;else {free(out);return NULL;}break;}}}*out_len = pos - out;return out;
}int main() {FILE* fp;char* base64_data;unsigned char* decoded_data;size_t decoded_len, base64_len;char* filename = "test.png"; // 替换为你的图片文件名char* output_filename = "decoded_image.png"; // 解码后保存的文件名// 读取图片文件fp = fopen(filename, "rb");if (!fp) {fprintf(stderr, "无法打开文件 %s\n", filename);return 1;}fseek(fp, 0, SEEK_END);base64_len = ftell(fp);fseek(fp, 0, SEEK_SET);unsigned char* image_data = (unsigned char*)malloc(base64_len);fread(image_data, 1, base64_len, fp);fclose(fp);// 将图片数据编码为Base64字符串base64_data = base64_encode(image_data, base64_len);free(image_data);if (!base64_data) {fprintf(stderr, "Base64 编码失败\n");return 1;}// 输出Base64编码后的数据printf("Base64 编码结果:\n%s\n", base64_data);// 解码Base64字符串为图片数据decoded_data = base64_decode(base64_data, &decoded_len);free(base64_data);if (!decoded_data) {fprintf(stderr, "Base64 解码失败\n");return 1;}// 将解码后的图片数据保存为文件fp = fopen(output_filename, "wb");if (!fp) {fprintf(stderr, "无法打开文件 %s 进行写入\n", output_filename);free(decoded_data);return 1;}fwrite(decoded_data, 1, decoded_len, fp);fclose(fp);free(decoded_data);printf("图片已成功解码并保存到 %s\n", output_filename);return 0;
}

这篇关于生成图片的base64编码(纯C语言实现)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1130160

相关文章

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一