使用 libjpeg 在 C++ 中旋转 JPEG 图像

2023-12-11

我正在尝试根据 EXIF 元数据中存在的“方向”参数,使用 libjpeg v9 在 C++ 中旋转 JPEG 图像。我能够获取“方向”参数,并在此基础上,我还能够将图像旋转到另一个文件中,以便旋转后的图像对应于“方向”值 1。

请参阅我从“jpegtran.c”文件中获取的代码并且工作正常(不存在读取 EXIF 元数据代码):

#include <iostream>
#include <jpeglib.h>
#include <jerror.h>

#include "transupp.h"

void setTransformation(jpeg_transform_info *transformObj, JXFORM_CODE transformation){
    transformObj->perfect = FALSE;
    transformObj->trim = FALSE;
    transformObj->force_grayscale = FALSE;
    transformObj->crop = FALSE;
    transformObj->transform = transformation;
}

void releaseRes(j_decompress_ptr srcPtr, j_compress_ptr destPtr){
    
    jpeg_finish_compress(destPtr);
    jpeg_destroy_compress(destPtr);

    (void) jpeg_finish_decompress(srcPtr);
    jpeg_destroy_decompress(srcPtr);
}

void rotateImage(const char *inputFilename, const char *outputFilename, JXFORM_CODE transformVal){

    FILE *inputFile = fopen(inputFilename, "r");
    if(inputFile==NULL){
        std::cerr<<"ERROR: cannot open input file\n";
        return;
    }

    struct jpeg_decompress_struct srcObj;
    struct jpeg_error_mgr srcErrMgr;
    
    struct jpeg_compress_struct destObj;
    struct jpeg_error_mgr destErrMgr;

    jvirt_barray_ptr *srcCoefArr;
    jvirt_barray_ptr *destCoefArr;

    //transformation object
    jpeg_transform_info transformObj;

    //set error handler
    srcObj.err = jpeg_std_error(&srcErrMgr);
    jpeg_create_decompress(&srcObj);

    destObj.err = jpeg_std_error(&destErrMgr);
    jpeg_create_compress(&destObj);

    //set the transformation properties
    setTransformation(&transformObj, transformVal);

    jpeg_stdio_src(&srcObj, inputFile);
    JCOPY_OPTION copyOpt = JCOPYOPT_DEFAULT;

    jcopy_markers_setup(&srcObj, copyOpt);

    (void) jpeg_read_header(&srcObj, TRUE);

    if(!jtransform_request_workspace(&srcObj, &transformObj)){
        std::cerr<<"Transformation is not perfect\n";
        return;
    }

    srcCoefArr = jpeg_read_coefficients(&srcObj);
    jpeg_copy_critical_parameters(&srcObj, &destObj);

    destCoefArr = jtransform_adjust_parameters(&srcObj, &destObj, srcCoefArr, &transformObj);

    FILE *outputFile = fopen(outputFilename, "wb");
    if(outputFile==NULL){
        std::cerr<<"ERROR: cannot open output file\n";
        fclose(inputFile);    
        releaseRes(&srcObj, &destObj);
        return;
    }

    jpeg_stdio_dest(&destObj, outputFile);

    jpeg_write_coefficients(&destObj, destCoefArr);

    jcopy_markers_execute(&srcObj, &destObj, copyOpt);

    jtransform_execute_transformation(&srcObj, &destObj, srcCoefArr, &transformObj);

    releaseRes(&srcObj, &destObj);
    //close files
    fclose(inputFile);
    fclose(outputFile);
}

但是,我不想将旋转图像存储到另一个文件中,而是想就地旋转到缓冲区或使用临时缓冲区,但不进行压缩,如上面的代码所示。

下面是将解压后的数据放入缓冲区的代码:

void rotateImage(const char *filename){
    FILE *file = fopen(filename, "r");
    if(!file){
        std::cerr<<"Error in reading file\n";
        return;
    }

    struct jpeg_decompress_struct info;
    struct jpeg_error_mgr jerr;
    
    info.err = jpeg_std_error(&jerr);

    jpeg_CreateDecompress(&info, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
        
    jpeg_stdio_src(&info, file);

    (void) jpeg_read_header(&info, TRUE);
    jpeg_start_decompress(&info);

    uint32_t channels = 3;
    uint32_t rowStride = info.output_width * channels;
    uint64_t dataSize = rowStride * info.output_height;

    unsigned char *buffer = new unsigned char[dataSize];
    unsigned char *rowData[1];

    while(info.output_scanline < info.output_height){
        //initial value of output_Scanline state var is 0
        rowData[0] = buffer + info.output_scanline * rowStride; 
        jpeg_read_scanlines(&info, rowData, 1);
    }

    /*Now, i want to rotate this buffer (or with other temp buffer without compression as in 
     first code) as per "orientation", either 90, 180, 270*/

    /* here */

    jpeg_finish_decompress(&info);
    jpeg_destroy_decompress(&info);
    fclose(file);
    delete buffer;
}

不过,我尝试使用临时缓冲区(类似于非方矩阵的矩阵旋转)通过以下代码旋转缓冲区 90 度:

//90 degree clockwise
unsigned char *tmpBuf = new unsigned char[dataSize];
int row = info.output_height;
int col = info.output_width;
for(int i=0; i<row; i+=1){
    for(int j=0;j<col; j+=1){
        //copied 3 bytes as each pixed takes 3 bytes for RGB
        memcpy(tmpBuf + (j*row + row-i-1)*3, buffer + (i*col + j)*3, 3);
    }
}

但是,我相信,这不是旋转 JPEG 的正确方法,因为我将此数据发送到的应用程序不接受旋转的数据(仅供参考,我按照应用程序尊重的“方向”旋转它)。这让我相信这不是旋转 JPEG 图像的正确方法。与第一种方法一样,我要向其发送数据的应用程序接受首先旋转为压缩数据,然后再次解压缩到缓冲区。但是,我认为,这不是更好的方法。

所以,我需要你的帮助。请让我知道实现它所需的步骤。任何代码示例或教程也会有所帮助。

Thanks


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 libjpeg 在 C++ 中旋转 JPEG 图像 的相关文章

  • 是否有与 posix_memalign 对应的 C++ 版本?

    当我打电话时posix memalign http man7 org linux man pages man3 posix memalign 3 html为类型的对象分配对齐的内存Foo在我的 C 代码中 我需要做一个reinterpret
  • 适合初学者的良好调试器教程[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有谁知道一个好的初学者教程 在 C 中使用调试器 我感觉自己好像错过了很多 我知道怎么做 单步执行代码并查看局部变量 虽然这常常给我带来问
  • 使用 C# 登录《我的世界》

    我正在尝试为自己和一些朋友创建一个简单的自定义 Minecraft 启动器 我不需要启动 Minecraft 的代码 只需要登录的实际代码行 例如 据我所知 您过去可以使用 string netResponse httpGET https
  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • 如何捕获未发送到 stdout 的命令行文本?

    我在项目中使用 LAME 命令行 mp3 编码器 我希望能够看到某人正在使用什么版本 如果我只执行 LAME exe 而不带参数 我会得到 例如 C LAME gt LAME exe LAME 32 bits version 3 98 2
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • 如何使用 Castle Windsor 将对象注入到 WCF IErrorHandler 实现中?

    我正在使用 WCF 开发一组服务 该应用程序正在使用 Castle Windsor 进行依赖注入 我添加了一个IErrorHandler通过属性添加到服务的实现 到目前为止一切正常 这IErrorHandler对象 一个名为FaultHan
  • 使用 LINQ to SQL 时避免连接超时的最佳实践

    我需要知道在 net 应用程序中使用 LINQ to SQL 时避免连接超时的最佳实践 特别是在返回时IQueryable
  • 在 NaN 情况下 to_string() 可以返回什么

    我使用 VS 2012 遇到了非常令人恼火的行为 有时我的浮点数是 NaN auto dbgHelp std to string myFloat dbgHelp最终包含5008角色 你不能发明这个东西 其中大部分为0 最终结果是 0 INF
  • C++ int 前面加 0 会改变整个值

    我有一个非常奇怪的问题 如果我像这样声明一个 int int time 0110 然后将其显示到控制台返回的值为72 但是当我删除前面的 0 时int time 110 然后控制台显示110正如预期的那样 我想知道两件事 首先 为什么它在
  • 保护 APK 中的字符串

    我正在使用 Xamarin 的 Mono for Android 开发一个 Android 应用程序 我目前正在努力使用 Google Play API 添加应用内购买功能 为此 我需要从我的应用程序内向 Google 发送公共许可证密钥
  • 等待 IAsyncResult 函数直至完成

    我需要创建等待 IAsyncResult 方法完成的机制 我怎样才能做到这一点 IAsyncResult result contactGroupServices BeginDeleteContact contactToRemove Uri
  • C++ new * char 不为空

    我有一个问题 我在 ASIO 中开发服务器 数据包采用尖头字符 当我创建新字符时 例如char buffer new char 128 我必须手动将其清理为空 By for int i 0 i lt 128 i buffer i 0x00
  • 将数组作为参数传递

    如果我们修改作为方法内参数传递的数组的内容 则修改是在参数的副本而不是原始参数上完成的 因此结果不可见 当我们调用具有引用类型参数的方法时 会发生什么过程 这是我想问的代码示例 using System namespace Value Re
  • GCC 的“-Wl,option”和“-Xlinker option”语法之间有区别吗?

    我一直在查看一些配置文件 并且看到它们都被使用 尽管在不同的体系结构上 如果您在 Linux 机器上使用 GCC 将选项传递给链接器的两种语法之间有区别吗 据我所知 阅读 GCC 手册时 他们的解释几乎相同 From man gcc Xli
  • 如何减少具有多个单元的 PdfPTable 的内存消耗

    我正在使用 ITextSharp 创建一个 PDF 它由单个 PdfTable 组成 不幸的是 对于特定的数据集 由于创建了大量 PdfPCell 我遇到了内存不足异常 我已经分析了内存使用情况 我有近百万个单元格的 1 2 在这种情况下有
  • 灵气序列解析问题

    我在使用 Spirit Qi 2 4 编写解析器时遇到一些问题 我有一系列键值对以以下格式解析
  • 是否可以在不连接数据库的情况下检索 MetadataWorkspace?

    我正在编写一个需要遍历实体框架的测试库MetadataWorkspace对于给定的DbContext类型 但是 由于这是一个测试库 我宁愿不连接到数据库 它引入了测试环境中可能无法使用的依赖项 当我尝试获取参考时MetadataWorksp
  • 如何使用 C++11 using 语法键入定义函数指针?

    我想写这个 typedef void FunctionPtr using using 我该怎么做呢 它具有类似的语法 只不过您从指针中删除了标识符 using FunctionPtr void 这是一个Example http ideone
  • 如何将十六进制字符串转换为无符号长整型?

    我有以下十六进制值 CString str str T FFF000 如何将其转换为unsigned long 您可以使用strtol作用于常规 C 字符串的函数 它使用指定的基数将字符串转换为 long long l strtol str

随机推荐

  • Lisp 追加无法正常工作

    你好 我正在尝试将一个简单的元素附加到 Lisp 列表中 append queue1 pop stack1 我认为上面的代码会将 stack1 的第一个元素附加到queue1 做queue1需要非零吗 谢谢 Append returns连接
  • 为什么可变结构是“邪恶的”?

    在关于 SO 的讨论之后 我已经多次阅读了可变结构是 邪恶的 的评论 就像在这个问题的答案中一样 question C 中的可变性和结构的实际问题是什么 结构是值类型 这意味着它们在传递时会被复制 因此 如果您更改副本 您只会更改该副本 而
  • 如果导入 ipdb,python multiprocessing 进程会被 http 请求杀死

    看起来只是简单的导入ipdb当发出一个封装在 a 中的 http 请求时multiprocessing Process实例导致程序退出 没有错误或消息 以下脚本的行为非常奇怪 from multiprocessing import Proc
  • Python:如何解决问题:Django 中的“格式错误的十六进制 UUID 字符串”

    我创建了 post 模型 其中包含 post id 作为主键字段 当我尝试创建帖子时 出现错误 十六进制 UUID 字符串格式错误 我将不胜感激帮助我解决这个问题 这是我的代码 模型 py class Post models Model p
  • PHP 脚本可以在没有客户端请求的情况下在服务器上定期运行吗?

    我将编写一个脚本来将文本文档解析到 MySQL 数据库中 我将使用单独的实用程序将 PDF 转换为文本 这些 PDF 文件将通过电子邮件附件提交 我想看看是否可以使用 PHP 来做到这一点 因为这是我最熟悉的服务器语言 第二个选择是 Per
  • 直流交叉滤波器不工作

    在这里使用 dc 和 cross filter js 库构建一个 grails 应用程序 但在可视化中遇到了一个极其奇怪的问题 我的可视化是 5 个条形图 它们使用 dc 和 cross filter js 库相互互连 所以 有简单的指标
  • 为什么我的 python 字典变得无序? [复制]

    这个问题在这里已经有答案了 我正在使用它来绘制多年来以某个字母开头的名称的百分比图 当绘制 和打印 我的词典 letter d 时 键是无序的 而不是像它们添加到词典中那样是连续的 有没有办法解决这个问题 我相信我正在按顺序将它们添加到字典
  • 为什么对 wp_postmeta 的引用这么慢?

    在 WordPress 中获取属性 使用 MySQL 似乎比必要的要慢 这是一个自我回答的问题 所以请继续我的回答 标准架构为wp postmeta提供较差的索引 这会导致性能问题 通过将架构更改为此 大多数对元数据的引用将会更快 CREA
  • Method.invoke 抛出 java.lang.IllegalArgumentException:参数数量错误

    public class ReflectionTest public static void main String args throws IllegalArgumentException IllegalAccessException I
  • 使用方括号 [] 初始化 std::vector ;怎么了?

    关于激发我的问题的背景信息 我了解了 C 中的指定初始值设定项 请参阅here和这里 https gcc gnu org onlinedocs gcc Designated Inits html 这太棒了 并且允许您像这样在 C 中初始化
  • 如何将一个句子分成两部分

    JAVA中如何将一个句子分成两部分 如果有以下情况 String sentence I love Java lt gt I love Python 我怎样才能返回I love Java and I love Python因此分别忽略 lt
  • 使用 SAS 中的数组将宽转为长

    我有一个 SAS 数据集 包含以下变量 ID Var1 0 Var1 3 Var1 6 Var2 0 Var2 3 Var2 6 可以这样读取 Var1 0 是时间 0 时的参数 1 对于每个主题 我有 2 个变量和 3 个时间点 我想使用
  • Excel 宏:浏览 Excel 文件并使用其工作表数据

    我写一个这样的脚本 Sub Button Click objFile Application GetOpenFilename fileFilter All Files choose load path Call main function
  • 使用一个表达式将两个变量分配给相同的值? [复制]

    这个问题在这里已经有答案了 有没有办法将两个变量分配给相同的值 刚刚尝试过这个 let x y hi 它正在编译为 use strict var x void 0 y hi 对的 这是可能的 let x y x y hi 这称为链接赋值 使
  • EXC_BAD_ACCESS 与 MKPinAnnotationView

    我在 iOS 的 mapView 上显示 MKPinAnnotationView 时遇到问题 我收到此错误 但我不明白错误来自何处 EXC BAD ACCESS 我的代码看起来不错 MKAnnotationView mapView MKMa
  • 如何找到hcaptcha回调函数

    所以我需要帮助在网站上查找 hcaptcha 回调函数 网站上没有提交按钮 所以我假设他们使用 hcaptcha 回调函数 该网站是https discord com register任何帮助将不胜感激 这段代码应该可以帮助你 https
  • 如何在 WAMPServer 中从 Windows 命令行运行 PHP

    我是 php 新手 想从命令行运行 php 我已经安装了 WAMP 并将 系统变量 设置为我的 php 文件夹 即C wamp bin php php5 4 3 当我去Run gt CMD gt 类型php a然后按回车键 它说intera
  • 在 EF Core 2.0 中使用 DataTable 作为表值参数

    更新问题描述 我们有一个批量导入流程 我们正在通过该流程IEnumerable
  • 如何使用像素RGB值0到1在java中编写PNG文件?

    我正在用 java 编写光线追踪器 并试图弄清楚如何将生成的图像写入 PNG 文件 到目前为止 我找到的所有示例都演示了如何使用 BufferedImage 创建 PNG 但它们都使用 RGB 值 0 到 255 在我的代码中 我表示 0
  • 使用 libjpeg 在 C++ 中旋转 JPEG 图像

    我正在尝试根据 EXIF 元数据中存在的 方向 参数 使用 libjpeg v9 在 C 中旋转 JPEG 图像 我能够获取 方向 参数 并在此基础上 我还能够将图像旋转到另一个文件中 以便旋转后的图像对应于 方向 值 1 请参阅我从 jp