使用另一个图像(temple.jpg)的压缩指纹压缩图像(org.jpg)

问题描述 投票:0回答:0

我有两张像素尺寸相同的图片:org.jpg 和 temple.jpg。我想完成以下任务:

  1. 使用temple.jpg的压缩指纹压缩org.jpg,生成新的图片target.jpg。
  2. 确保 target.jpg 中的 DQT(量化表)、SOF(帧起始)和 DHT(霍夫曼表)信息,包括十六进制代码(从 FFD8 到 FFDA)与 temple.jpg 中的相同。

我已经确保 org.jpg 和 temple.jpg 的像素尺寸相同。并尝试编写代码:


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

#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>


// Manually copy quantization table
void copy_quant_table(JQUANT_TBL* src, JQUANT_TBL* dst) {
    for (int i = 0; i < DCTSIZE2; i++) {
        dst->quantval[i] = src->quantval[i];
    }
}

// Manually copy huffman table
void copy_huff_table(JHUFF_TBL* src, JHUFF_TBL* dst) {
    for (int i = 0; i < 256; i++) {
        dst->bits[i] = src->bits[i];
        dst->huffval[i] = src->huffval[i];
    }
}


void custom_copy_critical_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo) {
    dstinfo->image_width = srcinfo->image_width;
    dstinfo->image_height = srcinfo->image_height;
    dstinfo->input_components = srcinfo->num_components;
    dstinfo->in_color_space = srcinfo->jpeg_color_space;

    jpeg_set_defaults(dstinfo);
    jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);

    dstinfo->data_precision = srcinfo->data_precision;
    dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;

    for (int ci = 0; ci < srcinfo->num_components; ci++) {
        jpeg_component_info* compptr = &srcinfo->comp_info[ci];
        jpeg_component_info* dstcompptr = &dstinfo->comp_info[ci];

        dstcompptr->h_samp_factor = compptr->h_samp_factor;
        dstcompptr->v_samp_factor = compptr->v_samp_factor;
    }
}
void replace_ffda_hex_code(const std::string& ref_filename, const std::string& output_filename) {
    // 打开参考文件和输出文件
    std::ifstream ref_file(ref_filename, std::ios::binary);
    std::ifstream output_file(output_filename, std::ios::binary);

    if (!ref_file || !output_file) {
        std::cerr << "Error opening files for hex code replacement." << std::endl;
        exit(1);
    }

    // 寻找FFDA标记
    const uint8_t marker_ff = 0xFF;
    const uint8_t marker_da = 0xDA;

    auto find_ffda_marker = [](std::ifstream& file) -> std::streampos {
        uint8_t byte1, byte2;
        byte1 = file.get();
        byte2 = file.get();

        while (!file.eof()) {
            if (byte1 == marker_ff && byte2 == marker_da) {
                return file.tellg() - std::streamoff(2);
            }
            byte1 = byte2;
            byte2 = file.get();
        }

        return std::streampos(-1);
    };

    // 在两个文件中找到FFDA标记的位置
    std::streampos ref_ffda_pos = find_ffda_marker(ref_file);
    std::streampos output_ffda_pos = find_ffda_marker(output_file);

    if (ref_ffda_pos == std::streampos(-1) || output_ffda_pos == std::streampos(-1)) {
        std::cerr << "FFDA marker not found in one of the files." << std::endl;
        exit(1);
    }

    // 创建临时文件以保存修改后的输出文件内容
    std::ofstream temp_file("temp_output.jpg", std::ios::binary);
    if (!temp_file) {
        std::cerr << "Error creating temporary file." << std::endl;
        exit(1);
    }

    // 将参考文件的FFDA之前的内容复制到临时文件
    ref_file.seekg(0, std::ios::beg);
    std::copy_n(std::istreambuf_iterator<char>(ref_file), ref_ffda_pos, std::ostreambuf_iterator<char>(temp_file));

    // 将输出文件的FFDA之后的内容复制到临时文件
    output_file.seekg(output_ffda_pos, std::ios::beg);
    temp_file << output_file.rdbuf();

    // 关闭文件
    ref_file.close();
    output_file.close();
    temp_file.close();

    // 使用修改后的临时文件覆盖原始输出文件
    std::remove(output_filename.c_str());
    std::rename("temp_output.jpg", output_filename.c_str());
}


void Debug_output_decompress_Huffman_and_quantization(jpeg_decompress_struct& info, const std::string& name) {
    std::cout << name << std::endl << " Quantization tables:" << std::endl;
    for (int i = 0; i < NUM_QUANT_TBLS; i++) {
        std::cout << "Table " << i << ": ";
        if (info.quant_tbl_ptrs[i] != nullptr) {
            for (int j = 0; j < DCTSIZE2; j++) {
                std::cout << info.quant_tbl_ptrs[i]->quantval[j] << " ";
            }
        }
        std::cout << std::endl;
    }

    std::cout << name << " Huffman tables:" << std::endl;
    for (int i = 0; i < NUM_HUFF_TBLS; i++) {
        std::cout << "Table " << i << ": ";
        if (info.dc_huff_tbl_ptrs[i] != nullptr) {
            std::cout << "DC Table " << i << " bits: ";
            for (int j = 0; j < 17; j++) {
                std::cout << (int)info.dc_huff_tbl_ptrs[i]->bits[j] << " ";
            }
            std::cout << " values: ";
            for (int j = 0; j < 256; j++) {
                std::cout << (int)info.dc_huff_tbl_ptrs[i]->huffval[j] << " ";
            }
        }
        std::cout << std::endl;
        if (info.ac_huff_tbl_ptrs[i] != nullptr) {
            std::cout << "AC Table " << i << " bits: ";
            for (int j = 0; j < 17; j++) {
                std::cout << (int)info.ac_huff_tbl_ptrs[i]->bits[j] << " ";
            }
            std::cout << " values: ";
            for (int j = 0; j < 256; j++) {
                std::cout << (int)info.ac_huff_tbl_ptrs[i]->huffval[j] << " ";
            }
        }

        
        std::cout << std::endl;
        
    }
    std::cout << "**---------------finish output---------------**" << std::endl;
    std::cout << std::endl;
}


void Debug_output_compress_Huffman_and_quantization(jpeg_compress_struct& info, const std::string& name) {
    std::cout << name << std::endl << "     Quantization tables:" << std::endl;
    for (int i = 0; i < NUM_QUANT_TBLS; i++) {
        std::cout << "Table " << i << ": ";
        if (info.quant_tbl_ptrs[i] != nullptr) {
            for (int j = 0; j < DCTSIZE2; j++) {
                std::cout << info.quant_tbl_ptrs[i]->quantval[j] << " ";
            }
        }
        std::cout << std::endl;
    }

    std::cout << name << " Huffman tables:" << std::endl;
    for (int i = 0; i < NUM_HUFF_TBLS; i++) {
        std::cout << "Table " << i << ": ";
        if (info.dc_huff_tbl_ptrs[i] != nullptr) {
            std::cout << "DC Table " << i << " bits: ";
            for (int j = 0; j < 17; j++) {
                std::cout << (int)info.dc_huff_tbl_ptrs[i]->bits[j] << " ";
            }
            std::cout << " values: ";
            for (int j = 0; j < 256; j++) {
                std::cout << (int)info.dc_huff_tbl_ptrs[i]->huffval[j] << " ";
            }
        }
        std::cout << std::endl;
        if (info.ac_huff_tbl_ptrs[i] != nullptr) {
            std::cout << "AC Table " << i << " bits: ";
            for (int j = 0; j < 17; j++) {
                std::cout << (int)info.ac_huff_tbl_ptrs[i]->bits[j] << " ";
            }
            std::cout << " values: ";
            for (int j = 0; j < 256; j++) {
                std::cout << (int)info.ac_huff_tbl_ptrs[i]->huffval[j] << " ";
            }
        }
        std::cout << std::endl;
        
    }
    std::cout << "**---------------finish output---------------**" << std::endl;
    std::cout << std::endl;
}


void copy_jpeg_file(const std::string& input_filename, const std::string& ref_filename, const std::string& output_filename) {
    // Open input and reference files
    FILE* input_file;
    FILE* ref_file;
    errno_t err;

    err = fopen_s(&input_file, input_filename.c_str(), "rb");
    err = fopen_s(&ref_file, ref_filename.c_str(), "rb");
    if (!input_file || !ref_file) {
        std::cerr << "Error opening files." << std::endl;
        exit(1);
    }

    // Input image decompression
    struct jpeg_decompress_struct srcinfo;
    struct jpeg_error_mgr srcerr;
    srcinfo.err = jpeg_std_error(&srcerr);
    jpeg_create_decompress(&srcinfo);

   

    jpeg_stdio_src(&srcinfo, input_file);
    jpeg_read_header(&srcinfo, TRUE);

    // Reference image decompression
    struct jpeg_decompress_struct refinfo;
    struct jpeg_error_mgr referr;
    refinfo.err = jpeg_std_error(&referr);
    jpeg_create_decompress(&refinfo);

    jpeg_stdio_src(&refinfo, ref_file);
    jpeg_read_header(&refinfo, TRUE);

    // Output image compression
    struct jpeg_compress_struct dstinfo;
    struct jpeg_error_mgr dsterr;
    dstinfo.err = jpeg_std_error(&dsterr);
    jpeg_create_compress(&dstinfo);

    FILE* output_file;
    err = fopen_s(&output_file, output_filename.c_str(), "wb");
    if (!output_file) {
        std::cerr << "Error opening output file." << std::endl;
        exit(1);
    }

  

    jpeg_stdio_dest(&dstinfo, output_file);     
 
    custom_copy_critical_parameters(&refinfo, &dstinfo);

    // Set input color space for output image
    dstinfo.in_color_space = srcinfo.out_color_space;

    // Disable JFIF header
    dstinfo.write_JFIF_header = FALSE;
    
    dstinfo.optimize_coding = FALSE;
    dstinfo.smoothing_factor = 0;
    dstinfo.dct_method = JDCT_ISLOW;

    dstinfo.comp_info[0].h_samp_factor = refinfo.comp_info[0].h_samp_factor;
    dstinfo.comp_info[0].v_samp_factor = refinfo.comp_info[0].v_samp_factor;
    dstinfo.comp_info[1].h_samp_factor = refinfo.comp_info[1].h_samp_factor;
    dstinfo.comp_info[1].v_samp_factor = refinfo.comp_info[1].v_samp_factor;
    dstinfo.comp_info[2].h_samp_factor = refinfo.comp_info[2].h_samp_factor;
    dstinfo.comp_info[2].v_samp_factor = refinfo.comp_info[2].v_samp_factor;

    Debug_output_compress_Huffman_and_quantization(dstinfo, "dstinfo huff_table and quant_table before copied");

    // Copy DQT、SOF and DHT 
    for (int i = 0; i < NUM_QUANT_TBLS; i++) {
        if (refinfo.quant_tbl_ptrs[i] != nullptr) {
            if (dstinfo.quant_tbl_ptrs[i] == nullptr) {
                dstinfo.quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)&dstinfo);
            }
            copy_quant_table(refinfo.quant_tbl_ptrs[i], dstinfo.quant_tbl_ptrs[i]);
        }
    }

    for (int i = 0; i < NUM_HUFF_TBLS; i++) {
        if (refinfo.dc_huff_tbl_ptrs[i] != nullptr) {
            if (dstinfo.dc_huff_tbl_ptrs[i] == nullptr) {
                dstinfo.dc_huff_tbl_ptrs[i] = jpeg_alloc_huff_table((j_common_ptr)&dstinfo);
            }
            copy_huff_table(refinfo.dc_huff_tbl_ptrs[i], dstinfo.dc_huff_tbl_ptrs[i]);
        }
        if (refinfo.ac_huff_tbl_ptrs[i] != nullptr) {
            if (dstinfo.ac_huff_tbl_ptrs[i] == nullptr) {
                dstinfo.ac_huff_tbl_ptrs[i] = jpeg_alloc_huff_table((j_common_ptr)&dstinfo);
            }
            copy_huff_table(refinfo.ac_huff_tbl_ptrs[i], dstinfo.ac_huff_tbl_ptrs[i]);
        }
    }


    Debug_output_decompress_Huffman_and_quantization(srcinfo, "srcinfo huff_table and quant_table after copied");
    Debug_output_compress_Huffman_and_quantization(dstinfo, "dstinfo huff_table and quant_table after copied");
    Debug_output_decompress_Huffman_and_quantization(refinfo, "refinfo huff_table and quant_table after copied");
     

    // Start decompression of input image and compression of output image
    jpeg_start_decompress(&srcinfo);

    jpeg_start_compress(&dstinfo, TRUE);

    // Allocate memory for scanlines buffer
    JSAMPARRAY buffer = (*srcinfo.mem->alloc_sarray)((j_common_ptr)&srcinfo, JPOOL_IMAGE, srcinfo.output_width * srcinfo.output_components, 1);

    // Copy scanlines from input image to output image
    while (srcinfo.output_scanline < srcinfo.output_height) {
        jpeg_read_scanlines(&srcinfo, buffer, 1);
        jpeg_write_scanlines(&dstinfo, buffer, 1);
    }

    // Finish decompression and compression
    jpeg_finish_decompress(&srcinfo);
    jpeg_finish_compress(&dstinfo);

    // Destroy structures and close files
    jpeg_destroy_decompress(&srcinfo);
    jpeg_destroy_decompress(&refinfo);
    jpeg_destroy_compress(&dstinfo);

    fclose(input_file);
    fclose(ref_file);
    fclose(output_file);

    }



int main() {
    std::string input_filename = "org.JPG";
    std::string ref_filename = "temple.jpg";
    std::string output_filename = "target.jpg";

    // Copy critical parameters from temple.jpg to target.jpg
    copy_jpeg_file(input_filename, ref_filename, output_filename);

    //replace_ffda_hex_code(ref_filename, output_filename);

    return 0;
}

上面的代码已经生成了target.jpg,但其实经过对比,target.jpg和temple.jpg的HEX码还是不一样的。我不确定是什么导致了这种差异。我是不是哪里做错了什么?

Two image from the same camare,比较来自同一相机的两张图像,它们具有相同的压缩算法和相同的十六进制代码(从 FFD8 到 FFDA)

output result,这是“target.jpg”和“temple.jpg”的比较,两个图像的十六进制代码不一样,这就是我问的问题。

c++ libjpeg
© www.soinside.com 2019 - 2024. All rights reserved.