生成图片的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

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2