【编译构建】用cmake编译libjpeg动态库并实现转灰度图片

先编译出libjepg动态库

1、下载libjpeg源码:

https://github.com/libjpeg-turbo/libjpeg-turbo

2、编译出动态库或静态库

写一个编译脚本,用cmake构建。

shell 复制代码
#!/bin/bash

# 定义变量
SOURCE_DIR="/home/user/libjpeg-turbo-main"
BUILD_DIR="${SOURCE_DIR}/build"
INSTALL_DIR="/home/user/libjpeg-turbo-main"

# 创建并进入构建目录
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"

# 运行CMake命令
cmake -G"Unix Makefiles" \
      -DCMAKE_BUILD_TYPE=Release \
      -DWITH_MEM_SRCDST=1 \
      -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \
      "$SOURCE_DIR"

# 编译和安装
make -j$(nproc)
sudo make install

# 提示完成
echo "Build and installation completed successfully!"

chmod +x ./libjpeg_build.sh

./libjpeg_build.sh

run!

编译生成的动态库安装在libjpeg-turbo-main/lib目录下 。

3、写代码

动态库有两种加载方式,一种编译的时候就依赖,一种是运行的时候dlopen。

写一个代码用turbo提供的接口实现一个彩色图片转灰度的图片的demo。

3.1 编译的时候就依赖

写CMakeLists.txt

c 复制代码
cmake_minimum_required(VERSION 3.10)
project(libjpeg_demo)

set(JPEG_LIB_DIR "/home/user/libjpeg-turbo-main/lib")
set(JPEG_INCLUDE_DIR "/home/user/libjpeg-turbo-main/include")

include_directories(${JPEG_INCLUDE_DIR})
link_directories(${JPEG_LIB_DIR})

add_executable(libjpeg_demo main.cpp)
target_link_libraries(libjpeg_demo turbojpeg)

cpp代码

cpp 复制代码
#include <turbojpeg.h>
#include <iostream>
#include <fstream>
#include <vector>

void saveGrayscaleImage(const std::string &filename, const unsigned char* buffer, int width, int height) {
    std::ofstream outFile(filename, std::ios::binary);
    outFile << "P5\n" << width << " " << height << "\n255\n";
    outFile.write(reinterpret_cast<const char*>(buffer), width * height);
    outFile.close();
}

int main() {
    const char* inputFile = "1.jpg";
    tjhandle jpegDecompressor = tjInitDecompress();
    std::ifstream inFile(inputFile, std::ios::binary | std::ios::ate);
    if (!inFile) {
        std::cerr << "Error: Could not open input file!" << std::endl;
        return 1;
    }

    std::streamsize fileSize = inFile.tellg();
    inFile.seekg(0, std::ios::beg);
    std::vector<unsigned char> jpegBuffer(fileSize);
    inFile.read(reinterpret_cast<char*>(jpegBuffer.data()), fileSize);

    int width, height, jpegSubsamp;
    tjDecompressHeader2(jpegDecompressor, jpegBuffer.data(), fileSize, &width, &height, &jpegSubsamp);

    std::vector<unsigned char> grayscaleBuffer(width * height);
    tjDecompress2(jpegDecompressor, jpegBuffer.data(), fileSize, grayscaleBuffer.data(), width, 0, height, TJPF_GRAY, TJFLAG_FASTDCT);

    saveGrayscaleImage("grayscale.pgm", grayscaleBuffer.data(), width, height);

    tjDestroy(jpegDecompressor);
    std::cout << "Grayscale image saved as grayscale.pgm" << std::endl;
    return 0;
}
3.2 通过dlopen动态加载

写CMakeLists.txt

c 复制代码
cmake_minimum_required(VERSION 3.10)
project(libjpeg_dl_demo)

set(CMAKE_CXX_STANDARD 17)

add_executable(libjpeg_dl_demo main.cpp)
target_link_libraries(libjpeg_dl_demo dl)
cpp 复制代码
#include <dlfcn.h>
#include <iostream>
#include <fstream>
#include <vector>
#include "turbojpeg.h"

// 定义动态加载的函数指针类型
typedef void* tjhandle;
typedef tjhandle (*tjInitDecompress_t)();
typedef int (*tjDecompressHeader2_t)(tjhandle, unsigned char*, unsigned long, int*, int*, int*);
typedef int (*tjDecompress2_t)(tjhandle, unsigned char*, unsigned long, unsigned char*, int, int, int, int, int);
typedef int (*tjDestroy_t)(tjhandle);

// 保存灰度图像为 PGM 格式
void saveGrayscaleImage(const std::string &filename, const unsigned char* buffer, int width, int height) {
    std::ofstream outFile(filename, std::ios::binary);
    outFile << "P5\n" << width << " " << height << "\n255\n";
    outFile.write(reinterpret_cast<const char*>(buffer), width * height);
    outFile.close();
}

int main() {
    const char* inputFile = "/home/user/demo/1.jpg";  // 输入文件路径

    // 动态加载 libturbojpeg.so 库
    void* handle = dlopen("/home/user/libjpeg-turbo-main/lib/libturbojpeg.so.0.4.0", RTLD_LAZY);
    if (!handle) {
        std::cerr << "Error loading tjInitDecompress: " << dlerror() << std::endl;
        return 1;
    }

    // 获取函数指针
    auto tjInitDecompress = (tjInitDecompress_t)dlsym(handle, "tjInitDecompress");
    auto tjDecompressHeader2 = (tjDecompressHeader2_t)dlsym(handle, "tjDecompressHeader2");
    auto tjDecompress2 = (tjDecompress2_t)dlsym(handle, "tjDecompress2");
    auto tjDestroy = (tjDestroy_t)dlsym(handle, "tjDestroy");

    if (!tjInitDecompress || !tjDecompressHeader2 || !tjDecompress2 || !tjDestroy) {
        std::cerr << "Error: Failed to load necessary functions from libturbojpeg.so" << std::endl;
        dlclose(handle);
        return 1;
    }

    // 初始化解压器
    tjhandle jpegDecompressor = tjInitDecompress();
    if (!jpegDecompressor) {
        std::cerr << "Error: Failed to initialize decompressor" << std::endl;
        dlclose(handle);
        return 1;
    }

    // 打开输入文件
    std::ifstream inFile(inputFile, std::ios::binary | std::ios::ate);
    if (!inFile) {
        std::cerr << "Error: Could not open input file!" << std::endl;
        tjDestroy(jpegDecompressor);
        dlclose(handle);
        return 1;
    }

    // 读取 JPEG 文件内容
    std::streamsize fileSize = inFile.tellg();
    inFile.seekg(0, std::ios::beg);
    std::vector<unsigned char> jpegBuffer(fileSize);
    inFile.read(reinterpret_cast<char*>(jpegBuffer.data()), fileSize);

    // 解压 JPEG header 获取图像尺寸
    int width, height, jpegSubsamp;
    if (tjDecompressHeader2(jpegDecompressor, jpegBuffer.data(), fileSize, &width, &height, &jpegSubsamp) != 0) {
        std::cerr << "Error: Failed to read JPEG header" << std::endl;
        tjDestroy(jpegDecompressor);
        dlclose(handle);
        return 1;
    }

    // 解压 JPEG 为灰度图像
    std::vector<unsigned char> grayscaleBuffer(width * height);
    if (tjDecompress2(jpegDecompressor, jpegBuffer.data(), fileSize, grayscaleBuffer.data(), width, 0, height, TJPF_GRAY, 0) != 0) {
        std::cerr << "Error: Failed to decompress image to grayscale" << std::endl;
        tjDestroy(jpegDecompressor);
        dlclose(handle);
        return 1;
    }

    // 保存灰度图像为 PGM 格式
    saveGrayscaleImage("grayscale.pgm", grayscaleBuffer.data(), width, height);

    // 清理资源并关闭库
    tjDestroy(jpegDecompressor);
    dlclose(handle);

    std::cout << "Grayscale image saved as grayscale.pgm" << std::endl;
    return 0;
}

写完

cd build

cmake ...

make

./libjpeg_dl_demo

跑起来啦

ok~

相关推荐
坐怀不乱杯魂5 分钟前
Linux - 进程控制
linux·运维·服务器
淦。。。。9 分钟前
题解:P14013 [POCamp 2023] 送钱 / The Generous Traveler
开发语言·c++·经验分享·学习·其他·娱乐·新浪微博
天赐学c语言19 分钟前
1.18 - 滑动窗口最大值 && 子类的指针转换为父类的指针,指针的值是否会改变
数据结构·c++·算法·leecode
重生之绝世牛码25 分钟前
Linux软件安装 —— zookeeper集群安装
大数据·linux·运维·服务器·zookeeper·软件安装
额12936 分钟前
磁盘物理卷、卷组、逻辑卷管理
linux·运维·服务器
Maggie_ssss_supp37 分钟前
Linux-正则表达式
linux·运维·正则表达式
是娇娇公主~38 分钟前
C++集群聊天服务器(3)—— 项目数据库以及表的设计
服务器·数据库·c++
重生之绝世牛码1 小时前
Linux软件安装 —— kafka集群安装(SASL密码验证)
大数据·linux·运维·服务器·分布式·kafka·软件安装
努力的小帅1 小时前
Linux_多线程(Linux入门到精通)
linux·多线程·多进程·线程同步·线程互斥·生产消费者模型
晴天¥1 小时前
操作系统由MBR->GPT,导致系统黑屏是怎么回事?
linux