如何以编程方式(.net)以无损方式将多个JPEG合并为更大的JPEG [英] How to combine several JPEGs into a bigger JPEG in a lossless way programmaticaly (.net)

查看:129
本文介绍了如何以编程方式(.net)以无损方式将多个JPEG合并为更大的JPEG的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几张JPEG图像,我想将它们合并为一张大JPEG图像.

I have several JPEG images and I want to combine them into one big JPEG image.

我可以通过创建一个Bitmap并将其组合在一起来做到这一点,但是如果我再次将其另存为JPEG,图像会变差.

I can do that by creating a Bitmap and then combining them there but that way if I save it again as JPEG the image will deteriorate.

那么,在解码/编码时我有什么方法可以使用而又不会损失质量吗?

So, is there any method that I can use to do that without losing quality while decoding/encoding?

在ACDSee程序中,我看到了一个旋转JPEG而不损失质量的选项,因此可能有一种方法可以合并多个图像而不损失质量.

In ACDSee program I saw an option to rotate JPEGs without quality loss, so there might be a way to combine several images without losing quality.

谢谢

推荐答案

好,我已经编写了代码,所以我想在这里分享它:)
请注意,该代码无法在所有情况下均能正常工作,但我可以使用.
我正在使用LibJpeg.Net库 http://bitmiracle.com/libjpeg .
库中还有一个错误(或我的错误:)),您无法获取组件height_in_blocks,这就是为什么该代码仅适用于正方形瓷砖的原因. 我认为这些图像必须具有与Vlasta所述相同的量化表.
我认为可以扩展此代码来支持该代码,但是我并不需要这种支持.
现在是代码:)

well i have written the code and so i wanted to share it here:)
please note that the code wont work on all situations but its fine for my use.
i am using the LibJpeg.Net library http://bitmiracle.com/libjpeg .
also there is a bug in the library (or a bug in me:) ) that you cant get the component height_in_blocks this is why that code will only work on square tiles.
i think that the images need to have the same quantization table as Vlasta mentioned.
i think this code can be expanded to support that but well i didnt need such support.
and now here comes the code :)

public void CreateBigImage()
{
    const int iTileWidth = 256;
    const int iTileHeigth = 256;
    int iImageWidthInTiles = 2;
    int iImageHeigthInTiles = 2;

    //Open Image to read its header in the new image
    BitMiracle.LibJpeg.Classic.jpeg_decompress_struct objJpegDecompressHeader = new BitMiracle.LibJpeg.Classic.jpeg_decompress_struct();
    System.IO.FileStream objFileStreamHeaderImage = new System.IO.FileStream(GetImagePath(0), System.IO.FileMode.Open, System.IO.FileAccess.Read);
    objJpegDecompressHeader.jpeg_stdio_src(objFileStreamHeaderImage);
    objJpegDecompressHeader.jpeg_read_header(true);

    BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[] varrJBlockBigImage = new BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[10];
    for (int i = 0; i < 3; i++)//3 compounds per image (YCbCr)
    {
        int iComponentWidthInBlocks = objJpegDecompressHeader.Comp_info[i].Width_in_blocks;
        int iComponentHeigthInBlocks = iComponentWidthInBlocks;//there is no Height_in_blocks in the library so will use widht for heigth also (wont work if image is not rectangular)
        varrJBlockBigImage[i] = BitMiracle.LibJpeg.Classic.jpeg_common_struct.CreateBlocksArray(iComponentWidthInBlocks * iImageWidthInTiles, iComponentHeigthInBlocks * iImageHeigthInTiles);
    }

    for (int iX = 0; iX < iImageWidthInTiles; iX++)
    {
        for (int iY = 0; iY < iImageHeigthInTiles; iY++)
        {
            WriteImageToJBlockArr(varrJBlockBigImage, GetImagePath(iY*iImageHeigthInTiles+iX), iX, iY);
        }
    }

    System.IO.FileStream objFileStreamMegaMap = System.IO.File.Create(GetImagePath(999));
    BitMiracle.LibJpeg.Classic.jpeg_compress_struct objJpegCompress = new BitMiracle.LibJpeg.Classic.jpeg_compress_struct();
    objJpegCompress.jpeg_stdio_dest(objFileStreamMegaMap);
    objJpegDecompressHeader.jpeg_copy_critical_parameters(objJpegCompress);//will copy the critical parameter from the header image
    objJpegCompress.Image_height = iTileHeigth * iImageHeigthInTiles;
    objJpegCompress.Image_width = iTileWidth * iImageWidthInTiles;
    objJpegCompress.jpeg_write_coefficients(varrJBlockBigImage);
    objJpegCompress.jpeg_finish_compress();
    objFileStreamMegaMap.Close();

    objJpegDecompressHeader.jpeg_abort_decompress();
    objFileStreamHeaderImage.Close();
}

public void WriteImageToJBlockArr(BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[] varrJBlockNew, string strImagePath, int iTileX, int iTileY)
{
    BitMiracle.LibJpeg.Classic.jpeg_decompress_struct objJpegDecompress = new BitMiracle.LibJpeg.Classic.jpeg_decompress_struct();
    System.IO.FileStream objFileStreamImage = new System.IO.FileStream(strImagePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
    objJpegDecompress.jpeg_stdio_src(objFileStreamImage);
    objJpegDecompress.jpeg_read_header(true);
    BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[] varrJBlockOrg = objJpegDecompress.jpeg_read_coefficients();
    for (int i = 0; i < 3; i++)//3 compounds per image (YCbCr)
    {
        int iComponentWidthInBlocks = objJpegDecompress.Comp_info[i].Width_in_blocks;
        int iComponentHeigthInBlocks = iComponentWidthInBlocks;//there is no Height_in_blocks in the library so will use widht for heigth also (wont work if image is not rectangular)
        for (int iY = 0; iY < iComponentHeigthInBlocks; iY++)
        {
            for (int iX = 0; iX < iComponentWidthInBlocks; iX++)
            {
                varrJBlockNew[i].Access(iY + iTileY * iComponentHeigthInBlocks, 1)[0][iX + iTileX * iComponentWidthInBlocks] = varrJBlockOrg[i].Access(iY, 1)[0][iX];
            }
        }
    }
    objJpegDecompress.jpeg_finish_decompress();
    objFileStreamImage.Close();
}

这篇关于如何以编程方式(.net)以无损方式将多个JPEG合并为更大的JPEG的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆