当前位置: 首页 > article >正文

丹青识画系统C语言基础:从零实现一个简单的图像文件解析器

丹青识画系统C语言基础从零实现一个简单的图像文件解析器想用C语言做点有趣的东西但又觉得控制台打印“Hello World”有点无聊今天我们来点不一样的——自己动手写一个能“看懂”图片的小程序。想象一下你写的代码能像丹青识画系统一样打开一张图片告诉你它的大小、颜色信息是不是感觉C语言瞬间就“活”了过来这个教程就是带你从零开始用最基础的C语言知识实现一个简单的图像文件解析器。我们不需要任何复杂的图形库就用标准库里的文件操作和内存管理去窥探BMP和PNG这两种常见图片格式的秘密。整个过程就像侦探破案一步步揭开图片文件头里隐藏的信息。学完它你不仅巩固了C语言的核心技能还能为将来理解更复杂的图像处理流程打下坚实的基础。1. 环境准备与目标设定在开始敲代码之前我们先明确两件事你需要准备什么以及我们最终要做出一个什么东西。你需要准备的东西很简单一台安装了C语言编译器的电脑比如Windows下的MinGW/GCC或者Mac/Linux自带的GCC。一个你喜欢的代码编辑器比如VS Code、CLion甚至记事本都行。几张用于测试的BMP和PNG格式的图片可以在画图工具里随便创建几张保存。我们的目标很明确写一个C语言程序它能读取用户指定的图片文件然后像个小助手一样在屏幕上打印出这张图片的“身份证信息”包括图片的格式是BMP还是PNG图片的宽度和高度有多大图片的色彩深度用了多少种颜色是黑白、彩色还是带透明度的别担心我们不会涉及复杂的图像解码和显示只聚焦在“读取文件头信息”这一步。这就像你拿到一个档案袋我们不拆开看里面详细的资料只通过档案袋封面上的标签来了解它的基本信息。2. 图像文件格式初探BMP与PNG图片在电脑里不是我们眼睛看到的样子而是一长串按照特定规则排列的字节。不同的规则就形成了不同的格式比如BMP和PNG。我们要当侦探首先得知道这两种“档案袋”的基本结构。BMP文件简单直白的“老派绅士”BMP格式是Windows系统下非常经典的一种图片格式它的结构非常规整几乎就是为C语言这种直接操作内存的语言量身定做的。一个BMP文件主要分为三大部分文件头就像档案袋最外面的封皮写着“这是BMP文件”以及整个文件有多大。信息头这是关键相当于档案袋里的第一页索引详细记录了图片的宽度、高度、色彩深度等重要信息。像素数据这才是图片的真正内容记录了每个像素点的颜色。不过我们今天的目标是读取信息头暂时不碰这部分。PNG文件功能强大的“现代青年”PNG格式更现代支持透明背景压缩效率也更高。它的结构稍微复杂一点采用了一种叫做“数据块”的结构。你可以把它想象成一个由多个乐高积木块拼接成的文件。每个“积木块”都有类型比如IHDR块存图像基本信息IDAT块存压缩后的图像数据。我们要找的图片尺寸、色彩深度等信息就存放在第一个关键的IHDR数据块里。了解这些我们就知道该去哪里找我们需要的信息了。接下来就是动手用C语言去“翻阅”这些档案。3. 搭建C语言解析器的骨架让我们先搭建一个清晰、安全的程序框架。一个好的框架能让后续的编码工作事半功倍也更容易排查错误。#include stdio.h #include stdlib.h #include string.h // 函数声明 void parseImageFile(const char* filename); int isBMPFile(FILE* file); int isPNGFile(FILE* file); void parseBMPHeader(FILE* file); void parsePNGHeader(FILE* file); int main(int argc, char* argv[]) { // 检查用户是否提供了文件名 if (argc 2) { printf(使用方法: %s 图片文件路径\n, argv[0]); printf(例如: %s test.bmp\n, argv[0]); return 1; // 非正常退出 } const char* filename argv[1]; parseImageFile(filename); return 0; // 正常退出 } // 主解析函数 void parseImageFile(const char* filename) { FILE* file fopen(filename, rb); // 以二进制只读模式打开文件 if (file NULL) { printf(错误无法打开文件 %s。请检查路径和文件名。\n, filename); return; } printf(正在分析文件: %s\n, filename); // 判断文件类型并调用相应的解析函数 if (isBMPFile(file)) { printf(文件格式: BMP\n); parseBMPHeader(file); } else if (isPNGFile(file)) { printf(文件格式: PNG\n); parsePNGHeader(file); } else { printf(错误不支持的文件格式或文件已损坏。\n); } fclose(file); // 千万别忘了关闭文件 }这段代码做了几件关键事包含必要的头文件stdio.h用于文件输入输出stdlib.h用于内存管理string.h用于字节比较。定义程序入口main函数检查命令行参数确保用户提供了要解析的图片路径。安全地打开文件使用fopen函数并以rb二进制读取模式打开这是处理图片等非文本文件的标准做法。清晰的函数分工我们声明了后续要实现的几个功能函数结构一目了然。资源管理使用fclose关闭文件这是一个非常重要的好习惯可以防止内存泄漏。现在程序的骨架已经搭好它知道怎么接收一个文件并且准备去判断它的类型。接下来我们来实现最有趣的部分——识别和解析。4. 实现BMP文件解析BMP格式的解析相对直观因为它的关键信息在文件中的位置是固定的。我们按照侦探的思路一步步来。4.1 识别BMP文件BMP文件的开头两个字节永远是‘B‘和‘M‘ASCII码。我们可以通过读取并比对这两个字节来快速判断。int isBMPFile(FILE* file) { unsigned char signature[2]; // 将文件指针重置到开头然后读取前2个字节 rewind(file); fread(signature, 1, 2, file); // 判断是否是 B 和 M return (signature[0] 0x42 signature[1] 0x4D); // 0x42B, 0x4DM }4.2 解析BMP信息头确认是BMP文件后我们需要跳过文件头前14字节直接定位到信息头开始的地方。BMP信息头有多个版本我们处理最常见的40字节的BITMAPINFOHEADER。void parseBMPHeader(FILE* file) { // 定义BMP信息头结构体40字节版本 #pragma pack(push, 1) // 确保编译器不对结构体成员进行内存对齐保证大小精确为40字节 typedef struct { unsigned int headerSize; // 本结构大小40 int width; // 图像宽度像素 int height; // 图像高度像素。正值表示倒序存储常见负值表示正序。 unsigned short planes; // 颜色平面数总是1 unsigned short bitCount; // 色彩深度每个像素位数如1,4,8,24 unsigned int compression; // 压缩方式0表示不压缩 unsigned int imageSize; // 图像数据大小字节 int xPixelsPerMeter; // 水平分辨率 int yPixelsPerMeter; // 垂直分辨率 unsigned int colorsUsed; // 实际使用的颜色索引数0表示使用全部 unsigned int colorsImportant; // 重要颜色索引数0表示都重要 } BitmapInfoHeader; #pragma pack(pop) BitmapInfoHeader infoHeader; // 跳过BMP文件头14字节定位到信息头开始处 fseek(file, 14, SEEK_SET); // 读取40字节的信息头数据到结构体中 fread(infoHeader, sizeof(BitmapInfoHeader), 1, file); // 打印解析出的信息 printf( BMP 图像信息 \n); printf(图像尺寸: %d x %d 像素\n, infoHeader.width, abs(infoHeader.height)); // 高度取绝对值 printf(色彩深度: %d 位/像素\n, infoHeader.bitCount); // 根据色彩深度解释颜色模式 switch(infoHeader.bitCount) { case 1: printf(颜色模式: 单色位图黑白\n); break; case 8: printf(颜色模式: 256色索引色\n); break; case 24: printf(颜色模式: 真彩色约1677万色\n); break; case 32: printf(颜色模式: 带Alpha通道的真彩色\n); break; default: printf(颜色模式: 其他 (%d位)\n, infoHeader.bitCount); } printf(压缩方式: %s\n, (infoHeader.compression 0) ? 无压缩 : 已压缩); }代码关键点解析#pragma pack指令这是为了确保我们定义的结构体在内存中紧密排列大小正好是40字节与BMP文件中的布局完全一致。否则编译器可能会为了内存对齐插入空隙导致读取错位。fseek函数用来移动文件指针。SEEK_SET表示从文件开头算起跳过14字节的文件头。fread函数一次性将40字节数据读入我们定义好的结构体变量中非常方便。abs(infoHeader.height)因为BMP文件通常倒序存储像素从下到上高度值常为负数。我们取绝对值来显示实际的像素高度。现在编译并运行你的程序指定一个BMP文件路径你应该能看到它的基本信息被打印出来了这感觉是不是很棒5. 实现PNG文件解析PNG的解析思路类似但因为它采用数据块结构我们需要先找到存放基本信息的IHDR块。5.1 识别PNG文件PNG文件的前8个字节是固定的签名Signature。int isPNGFile(FILE* file) { unsigned char signature[8]; const unsigned char pngSig[8] {137, 80, 78, 71, 13, 10, 26, 10}; // PNG文件签名 rewind(file); fread(signature, 1, 8, file); return (memcmp(signature, pngSig, 8) 0); // 比较前8个字节是否完全匹配 }5.2 定位并解析PNG的IHDR块PNG文件在8字节签名后紧跟着就是第一个数据块通常就是IHDR块。每个数据块由4部分组成数据长度(4字节)、块类型(4字节)、数据本身、循环冗余校验码(4字节)。void parsePNGHeader(FILE* file) { // 定义IHDR块数据结构13字节 #pragma pack(push, 1) typedef struct { unsigned int width; // 图像宽度像素 unsigned int height; // 图像高度像素 unsigned char bitDepth; // 色彩深度每个通道位数如1,2,4,8,16 unsigned char colorType; // 颜色类型决定通道构成 unsigned char compression; // 压缩方法目前总是0 unsigned char filter; // 滤波方法目前总是0 unsigned char interlace; // 隔行扫描方法0非隔行1Adam7隔行 } PngIHDR; #pragma pack(pop) PngIHDR ihdr; unsigned int chunkLength; char chunkType[5]; // 跳过PNG文件签名8字节 fseek(file, 8, SEEK_SET); // 读取第一个数据块的长度和类型 fread(chunkLength, 4, 1, file); // PNG文件使用大端字节序我们需要转换简单起见这里假设运行在常见的小端序系统上实际项目需处理 // chunkLength __builtin_bswap32(chunkLength); // 如果需要字节序转换 fread(chunkType, 1, 4, file); chunkType[4] \0; // 确保字符串结束 // 检查第一个块是否是IHDR if (strcmp(chunkType, IHDR) ! 0) { printf(错误PNG文件结构异常未找到IHDR块。\n); return; } // 读取IHDR块的数据部分13字节 fread(ihdr, sizeof(PngIHDR), 1, file); printf( PNG 图像信息 \n); printf(图像尺寸: %u x %u 像素\n, ihdr.width, ihdr.height); printf(位深度: %d 位/通道\n, ihdr.bitDepth); // 根据颜色类型解释图像模式 printf(颜色类型: ); switch(ihdr.colorType) { case 0: printf(灰度图); break; case 2: printf(真彩色(RGB)); break; case 3: printf(索引彩色); break; case 4: printf(带Alpha的灰度图); break; case 6: printf(带Alpha的真彩色(RGBA)); break; default: printf(未知(%d), ihdr.colorType); } printf(\n); // 计算总色彩深度近似 int totalBitsPerPixel; switch(ihdr.colorType) { case 0: totalBitsPerPixel ihdr.bitDepth * 1; break; // 灰度 case 2: totalBitsPerPixel ihdr.bitDepth * 3; break; // RGB case 3: totalBitsPerPixel ihdr.bitDepth; break; // 索引色实际来自调色板 case 4: totalBitsPerPixel ihdr.bitDepth * 2; break; // 灰度Alpha case 6: totalBitsPerPixel ihdr.bitDepth * 4; break; // RGBA default: totalBitsPerPixel 0; } if (totalBitsPerPixel 0) { printf(近似色彩深度: %d 位/像素\n, totalBitsPerPixel); } }PNG解析的注意事项字节序问题PNG格式采用大端字节序网络字节序而我们的电脑x86架构通常是小端序。上面代码为了简化暂时忽略了转换。在严谨的项目中需要使用ntohl或类似的函数进行转换。你可以把chunkLength __builtin_bswap32(chunkLength);这行代码的注释去掉并在支持它的编译器上使用。数据块遍历一个完整的PNG解析器需要依次读取所有数据块。我们的例子只读取了第一个应该是IHDR块这对于获取基本尺寸信息已经足够。6. 测试你的图像解析器代码写完了是时候看看它的成果了。找几张BMP和PNG图片放在你的程序可访问的目录下。编译程序以GCC为例gcc -o image_parser image_parser.c运行并测试# 解析一张BMP图片 ./image_parser sample.bmp # 解析一张PNG图片 ./image_parser sample.png如果一切顺利你的终端会输出类似这样的信息正在分析文件: sample.bmp 文件格式: BMP BMP 图像信息 图像尺寸: 800 x 600 像素 色彩深度: 24 位/像素 颜色模式: 真彩色约1677万色 压缩方式: 无压缩正在分析文件: sample.png 文件格式: PNG PNG 图像信息 图像尺寸: 1024 x 768 像素 位深度: 8 位/通道 颜色类型: 带Alpha的真彩色(RGBA) 近似色彩深度: 32 位/像素看到自己写的程序能正确识别并读出图片信息是不是很有成就感这就是编程的乐趣所在——用代码去理解和操作数字世界。7. 总结与下一步通过这个小小的项目我们实际上完成了一次非常典型的“系统编程”练习。我们直接与二进制文件格式打交道运用了结构体、文件I/O、内存布局控制等C语言核心知识最终实现了一个有实际用处的工具。这比单纯做算法题更能让你感受到C语言在底层系统、数据处理方面的强大能力。这个简单的解析器就像一个“丹青识画”系统的雏形它完成了最基础的一步读取图像元数据。在实际的图像处理库如OpenCV、libpng中后续的步骤会更加复杂包括解码像素数据、应用颜色空间转换、进行压缩/解压缩等。但万变不离其宗理解文件格式是这一切的基础。如果你想继续深入这里有几个方向可以尝试完善PNG解析正确处理字节序问题并尝试遍历文件中的所有数据块找出tEXt文本信息或iCCP色彩配置文件块。支持更多格式尝试解析JPEG文件的标记段Markers读取其尺寸信息SOF0段。这会涉及更复杂的流式解析。添加错误处理让程序对损坏的文件、不完整的文件头有更强的鲁棒性给出更清晰的错误提示。输出结构化信息将解析结果写入一个JSON或XML文件方便其他程序调用。编程的学习就是这样从一个能运行的小例子开始不断给它增加新的功能在这个过程中你的理解和能力也会像滚雪球一样增长。希望这个“丹青识画”的起点能带你进入更广阔的计算机图形与图像处理的世界。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

相关文章:

丹青识画系统C语言基础:从零实现一个简单的图像文件解析器

丹青识画系统C语言基础:从零实现一个简单的图像文件解析器 想用C语言做点有趣的东西,但又觉得控制台打印“Hello World”有点无聊?今天我们来点不一样的——自己动手写一个能“看懂”图片的小程序。想象一下,你写的代码能像丹青识…...

Spring Authorization Server实战 (一) 构建符合OAuth2.1规范的授权码与PKCE流程

1. 为什么需要OAuth2.1和PKCE? 十年前我刚接触OAuth2.0时,觉得这套协议简直完美解决了第三方应用授权问题。直到去年在项目中遇到真实的安全事件:一个SPA应用因为使用传统授权码模式,导致用户token被中间人截获。这才让我真正理解…...

基于Milo的Java OPC UA客户端实战:从配置Kepware到实现高并发数据订阅

1. 工业数据采集项目背景与OPC UA技术选型 在智能制造和工业4.0的浪潮下,工厂车间的设备数据采集成为MES系统实现生产管控的关键环节。我去年参与的一个汽车零部件生产线改造项目,就遇到了西门子S7-1500 PLC与MES系统实时通信的挑战。当时测试了多种通信…...

MongoDB副本集安全加固:手把手教你生成和配置keyfile(含权限设置避坑指南)

MongoDB副本集安全加固实战:从keyfile生成到权限管控的全链路指南 在分布式数据库架构中,MongoDB副本集的高可用特性使其成为企业级应用的首选方案。但当我们把目光投向生产环境时,安全认证环节往往成为最容易被忽视的薄弱点。许多团队在搭建…...

Kinect深度图补全黑科技:3D ShapeNets在AR/VR中的5个落地场景

Kinect深度图补全黑科技:3D ShapeNets在AR/VR中的5个落地场景 当Kinect的深度传感器捕捉到残缺的3D数据时,工程师们常常面临一个关键挑战:如何从局部信息推断完整的三维结构?这正是3D ShapeNets技术大显身手的时刻。这项基于深度学…...

Cursor AI代码编辑器实战:如何用自然语言快速构建全栈项目

Cursor AI代码编辑器实战:如何用自然语言快速构建全栈项目 第一次听说Cursor能通过聊天完成全栈开发时,我和大多数程序员一样持怀疑态度——直到亲眼见证同事用三句自然语言指令生成可运行的电商系统原型。这种震撼不亚于第一次看到Copilot自动补全整段代…...

PoolFormer实战:用平均池化替代注意力机制,如何在图像分类任务中跑出SOTA效果

PoolFormer实战:用平均池化重构视觉模型,突破图像分类效率瓶颈 当Transformer在计算机视觉领域大放异彩时,一个不容忽视的事实是:注意力机制带来的计算复杂度让许多实际应用望而却步。2022年出现的PoolFormer却反其道而行——用最…...

FreeRTOS系统时钟深度优化:如何根据项目需求调整configTICK_RATE_HZ参数

FreeRTOS系统时钟深度优化:如何根据项目需求调整configTICK_RATE_HZ参数 在嵌入式实时操作系统中,时间管理是核心功能之一。FreeRTOS作为一款轻量级RTOS,其系统时钟的配置直接影响任务调度、延时精度以及整体系统性能。configTICK_RATE_HZ这个…...

PyTorch稀疏张量实战:COO与CSR格式高效存储与计算指南

1. 稀疏张量入门:为什么需要特殊存储格式? 第一次接触稀疏张量这个概念时,我也曾疑惑:为什么普通的张量存储方式不够用?直到处理一个自然语言处理的词向量矩阵时,我才真正理解它的价值。想象一下&#xff0…...

解决Nextcloud外网访问报错:Docker容器内修改配置文件的3种方法

深度解析:Nextcloud容器化部署中的外网访问配置优化 引言 在当今数字化办公环境中,私有云存储解决方案越来越受到企业和个人用户的青睐。Nextcloud作为一款开源的私有云平台,凭借其丰富的功能模块和灵活的部署方式,成为众多技术爱…...

解决Android Studio安装时缺失Android SDK选项的完整指南

1. 为什么安装Android Studio时找不到SDK选项? 第一次安装Android Studio时,很多开发者都会遇到一个让人头疼的问题——在安装向导的组件选择界面,竟然找不到Android SDK的选项。这种情况我遇到过不止一次,特别是在Windows平台上安…...

Chromium指纹浏览器开发指南:核心模块功能解析与实战应用

1. Chromium指纹浏览器开发入门指南 第一次接触Chromium指纹浏览器开发时,我完全被庞大的代码库吓到了。但经过几个项目的实战后,我发现只要掌握核心模块,就能快速上手开发。Chromium指纹浏览器本质上是通过修改Chromium内核来实现浏览器指纹…...

信创中间件技术全景解析:从基础架构到行业实践

1. 信创中间件的技术架构解析 第一次接触信创中间件时,我被它复杂的架构搞得一头雾水。后来在实际项目中摸爬滚打才发现,中间件就像建筑工地上的脚手架——虽然不直接参与业务逻辑,但缺了它整个系统就会散架。 信创中间件的核心架构可以分为三…...

ZYNQ-7020嵌入式开发实战:基于ARM核的UART通信与“Hello World”调试全流程

1. ZYNQ-7020开发环境搭建 第一次接触ZYNQ-7020时,我被它独特的"处理器FPGA"架构深深吸引。作为Xilinx推出的明星产品,ZYNQ-7020内部集成了双核ARM Cortex-A9处理器和可编程逻辑单元,这种软硬件协同设计的特性让它成为嵌入式开发的…...

深入解析aarch64-linux-gnu交叉编译libpcap的常见陷阱与解决方案

1. 交叉编译环境搭建与工具链选择 为什么需要交叉编译? 当你在x86架构的PC上开发ARM架构(如树莓派、嵌入式设备)的程序时,直接编译生成的二进制文件无法在目标平台运行。这时就需要交叉编译器——一种能在A平台编译出B平台可执行…...

图图的嗨丝造相-Z-Image-Turbo部署案例:基于Xinference的GPU算力高效利用方案

图图的嗨丝造相-Z-Image-Turbo部署案例:基于Xinference的GPU算力高效利用方案 最近在玩AI绘画的朋友,可能都遇到过这样的烦恼:看到一个特别有意思的模型,比如能生成特定风格图片的模型,但部署起来特别麻烦。要么需要复…...

联邦学习遇上大语言模型:如何用私有数据训练LLM而不泄露隐私?

联邦学习与大语言模型的隐私保护融合:企业级实践指南 当ChatGPT等大语言模型(LLM)展现出惊人的文本生成能力时,医疗、金融、法律等领域的从业者却面临一个尴尬现实——这些行业最宝贵的私有数据因隐私合规要求,始终无法…...

Linux定时器实战:用timerfd_create和epoll打造高精度任务调度器(附完整代码)

Linux定时器实战:用timerfd_create和epoll打造高精度任务调度器(附完整代码) 在Linux服务器开发中,定时任务调度是一个永恒的话题。无论是网络连接超时检测、定期数据备份,还是实时监控系统状态,都需要精确…...

docx-preview避坑指南:解决Vue3中文件预览的三大常见问题

Vue3实战:docx-preview深度优化与问题破解手册 在Vue3项目中集成文档预览功能时,许多开发者会遇到这样的场景:从后端获取的docx文件需要在前端完美呈现,但实际开发中却频频遭遇样式崩坏、性能卡顿、跨域报错等问题。本文将分享三个…...

[具身智能-27]:具身智能中的长尾效应

长尾效应(The Long Tail) 是一个统计学和商业概念,由克里斯安德森(Chris Anderson)在2004年提出。在具身智能(Embodied AI)的语境下,它指的是:那些发生概率极低、种类极其…...

COMSOL求解器设置实战:从非线性问题到收敛技巧(附阻尼牛顿法配置)

COMSOL求解器深度优化指南:攻克非线性收敛难题的7个关键策略 在工程仿真领域,非线性问题的求解就像试图驯服一头难以捉摸的野兽——它可能突然变得不稳定、拒绝收敛,或者消耗大量计算资源却得不到理想结果。COMSOL Multiphysics作为多物理场耦…...

VB6.0老司机教你5分钟生成EXE文件(附调用宏程序完整代码)

VB6.0高效开发实战:从EXE生成到程序集成的完整指南 在当今快速迭代的软件开发环境中,虽然VB6.0已不再是主流选择,但仍有大量遗留系统和特定场景需要这一经典工具的支持。许多经验丰富的开发者发现,掌握VB6.0的高效开发技巧能够显著…...

[特殊字符] nanobot超轻量级AI助手5分钟部署教程:零基础搭建个人智能助手

Nanobot超轻量级AI助手5分钟部署教程:零基础搭建个人智能助手 1. 引言:为什么选择Nanobot? 你是否曾经想过拥有一个属于自己的AI助手,但又觉得部署过程太复杂?或者被动辄几十万行代码的开源项目吓退?Nano…...

语音情感识别新体验:Emotion2Vec+ Large WebUI界面功能全解析

语音情感识别新体验:Emotion2Vec Large WebUI界面功能全解析 1. 引言:当AI“听懂”你的情绪 想象一下,你正在开发一款智能客服系统。客户打来电话,语气里带着一丝不易察觉的焦虑。传统的语音转文字只能告诉你客户说了什么&#…...

STM32CubeIDE实战:光敏传感器自动调光系统(附完整代码)

STM32CubeIDE实战:光敏传感器自动调光系统(附完整代码) 在智能家居和工业自动化领域,自动调光系统正变得越来越普及。想象一下,当你走进房间时灯光自动亮起,离开时自动熄灭;或者温室大棚根据日照…...

Vue项目实战:用AiLabel.js打造图片标注功能(附完整代码下载)

Vue项目实战:用AiLabel.js打造智能图片标注系统 在计算机视觉和机器学习项目的前期准备中,数据标注是构建高质量训练集的关键环节。作为前端开发者,我们经常需要在Web应用中实现图片标注功能,让用户可以直观地标记图像中的关键区域…...

电脑USB接口不够用?手把手教你用USB集线器扩展接口(附设备连接优化技巧)

电脑USB接口不够用?手把手教你用USB集线器扩展接口(附设备连接优化技巧) 现代办公桌上总少不了键盘、鼠标、移动硬盘、打印机、手机充电线这些USB设备,但笔记本自带的接口往往捉襟见肘。上周我帮一位视频剪辑师调试设备时&#xf…...

聊天记录总消失?这款工具让消息永存

聊天记录总消失?这款工具让消息永存 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: https://gitcode.com/GitHub_Trending…...

反诈系统毕设实战:基于规则引擎与实时流处理的高可用架构设计

最近在帮学弟学妹们看毕设,发现不少“反诈系统”项目都卡在了几个老问题上:规则写死在代码里,改一点就要重新上线;数据来了只能批量处理,做不到实时预警;稍微复杂点的场景,误报率就蹭蹭往上涨。…...

XSS-Labs靶场通关秘籍:从入门到精通的20个实战技巧(附源码分析)

XSS-Labs靶场通关秘籍:从入门到精通的20个实战技巧(附源码分析) 在网络安全领域,跨站脚本攻击(XSS)始终是Web应用中最常见且危害性极大的漏洞类型之一。对于初学者而言,理论知识的积累固然重要&…...