JPEG image rotation in C++ using libjpeg

我的梦境 提交于 2020-12-27 02:23:41

问题


I am trying to rotate a JPEG image in C++ using libjpeg v9 based on the "Orientation" parameter present in EXIF metadata. I am able to get the "Orientation" parameter and on its basis, i am also able to rotate image into another file so that rotated image corresponds to "Orientation" value 1.

See code, which i have taken from "jpegtran.c" file and working fine(reading EXIF metadata code is not present):

#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);
}

However, i do not want to store rotated image into another file and rather want to rotate in place into buffer or using temp buffer but without compression as in above code.

Below is the code to get the decompressed data into buffer:

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;
}

Though, i tried to rotate buffer using temp buffer (analogous to matrix rotation for non-square matrix) with following code for 90 degree:

//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);
    }
}

However, i believe, it is not correct way for rotating JPEG as the rotated data is not accepted by the application i am sending this data to(FYI, i am rotating it as per "Orientation" as application respect it). Which makes me believe that it is not the correct way to rotate JPEG image. As with first method, first rotating into compressed data and then decompressing again into buffer is accepted by the application i am sending data to. But, i think, it is not the better way to do it.

So, i need your help for this. Please let me know the step required to achieve it. Any code example or tutorials will also be helpful.

Thanks

来源:https://stackoverflow.com/questions/64286451/jpeg-image-rotation-in-c-using-libjpeg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!