前言
由于项目需要,需要将jpg转换成TIFF,考虑到window下已经实现过,所以继续用cximage来进行图片转换。
过程
下载
请下载linux专版cximage599c
编译
文件修改
在编译之前,需要修改tif_xfile.cpp的源码,需要修改的内容网上一堆,但是我用ubuntu测试了下,都不行,对照了windows的源码,需要调整的红色标注如下:
TIFF*
_TIFFFdOpen(void* fd, const char* name, const char* mode)
{
TIFF* tif;
tif = TIFFClientOpen(name, mode,
(thandle_t) fd,
_tiffReadProcEx, _tiffWriteProcEx, _tiffSeekProcEx, _tiffCloseProcEx,
_tiffSizeProcEx, _tiffMapProcEx, _tiffUnmapProcEx);
if (tif)
tif->tif_fd =(long) fd;
return (tif);
}
extern “C” TIFF* _TIFFOpenEx(CxFile* stream, const char* mode)
{
return (_TIFFFdOpen((void*)stream, “TIFF IMAGE”, mode));
}
正式编译
由于直接直行sudo ./configure会报权限问题,按照如下进行重新生成:
#重新生成 aclocal.m4
aclocal
#重新生成configure文件
autoconf -i -v -f
#删除原来的makefile
find ./ -name Makefile -exec rm -rf {} \;
#重新生成Makefile
./configure
make
出现错误1:
configure:error cannot guess build type;you must specify one cximage
不能确定编译的操作系统
解决方法
在gcc编译中我们使用
./configure --build=编译平台 --host=运行平台 --target=目标平台
./configure --build=arm-linux --prefix=/usr
出现错误2:
error: C++ preprocessor “/lib/cpp” fails sanity check
是由于缺少C++库,解决方法
apt-get install build-essential
apt-get install g++
然后再
./configure
make
出现错误3:
configure.in:62: ‘automake --add-missing’ can install ‘compile’
make: *** [Makefile.in] Error 1
#解决方法,在终端里执行如下命令
automake --add-missing
make
出现错误4:
fatal error: jasper/jas_config.h: 没有那个文件或目录
#删除原来的 Makefile
find ./ -name Makefile -exec rm -rf {} \;
#添加–with-extra-includes指定头文件路径,重新生成Makefile
./configure --with-extra-includes=/home/cximage599c/cximage/jasper/include/
make clean
make
代码
以下工程用QT进行测试,请注意!
在pro文件夹加入如下链接
LIBS += -L $$PWD/lib -lCxImage -ljpeg -ltiff -lzlib -lpng -ljasper
在pro同级目录下创建Include、lib文件夹
将cximage599c/cximage目录下的相应文件拷贝到以上文件夹下面
整个工程的组织如下图:
下面展示 测试代码
。
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//#include "./include/ximage.h"
#include "./include/ximatif.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QStringList imgList_jpg;
imgList_jpg.append("scan_1.jpg");
imgList_jpg.append("scan_2.jpg");
QString strFolder("/home/redcolor/qt_study/cximage_link/jpg_convert");
QString strTIFF_jpg ;
#ifdef jpg2tif
CxImage image_jpg[2];
for(int i = 0 ; i < imgList_jpg.size();i++) {
QString szJpgAt = QString("%1/%2").arg(strFolder).arg(imgList_jpg.at(i));
if (image_jpg[i].Load((const char*)szJpgAt.toLocal8Bit().data(),CXIMAGE_FORMAT_JPG))
image_jpg[i].DecreaseBpp(4,0);
}
strTIFF_jpg = QString("%1/%2").arg(strFolder).arg("tiff_jpg.tif");
FILE* hFileTiff = fopen(strTIFF_jpg.toLocal8Bit().data(),_T("w+b"));
if (hFileTiff) {
int nIndex = 0 ;
CxImage* img[2];
img[nIndex] = &image_jpg[nIndex];nIndex++;
img[nIndex] = &image_jpg[nIndex];nIndex++;
CxImage image;
image.Encode(hFileTiff,img,nIndex,CXIMAGE_FORMAT_TIF);
fclose(hFileTiff);
}
#else
strTIFF_jpg = QString("%1/%2").arg(strFolder).arg("tiff_jpg_direct.tif");
FILE* hFileTiff = fopen(strTIFF_jpg.toLocal8Bit().data(),_T("w+b"));
if (hFileTiff) {
CxImageTIF image_tif;
for(int i = 0 ; i < imgList_jpg.size();i++) {
QString szJpgAt = QString("%1/%2").arg(strFolder).arg(imgList_jpg.at(i));
if (image_tif.Load((const char*)szJpgAt.toLocal8Bit().data(),CXIMAGE_FORMAT_JPG)){
image_tif.DecreaseBpp(4,0);
image_tif.Encode(hFileTiff,TRUE);
}
}
fclose(hFileTiff);
}
#endif
return 1;
}
上面的代码展示了2个jpg到tiff的转换方法,本质都是一样的,但是引用的库不一样,可以看头文件引用部分。
由于之前windows的代码是将jpg转换为bmp,再由bmp转换为TIFF文件,导致在Linux环境下一开始也是按照这种思路在推进,结果就是一顿baidu也没有找到解决方法(cximage599c里面的bmp完全不能用),没有办法我就按照windows的代码对Linux下的一顿魔改,最终可以实现load CXIMAGE_FORMAT_JPG 图片保存为CXIMAGE_FORMAT_BMP位图图片,也可以实现DecreaseBpp(1,0),但是只能实现位深度为1的压缩。
后来继续了解了下BMP、TIFF、JPG的图片格式,然后换了思路,直接用JPG转TIFF,先用源码尝试了下可行,然后又用静态库试了下也行,才有了这篇文章。
说实话,BMP魔改真实蛋疼,核心就是下面这个结构体
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
long biWidth;
long biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
改为如下结构体
typedef struct tagBITMAPINFOHEADER_WIN32{
UINT biSize;
UINT biWidth;
UINT biHeight;
WORD biPlanes;
WORD biBitCount;
UINT biCompression;
UINT biSizeImage;
UINT biXPelsPerMeter;
UINT biYPelsPerMeter;
UINT biClrUsed;
UINT biClrImportant;
} BITMAPINFOHEADER_WIN32;
本质就是位图信息格式长度不对,导致解析失败,对应的就是decode和encode里面的地址偏移量的问题了。其中bool CxImageBMP::Encode(CxFile * hFile)部分的魔改代码如下
BITMAPFILEHEADER hdr;
hdr.bfType = 0x4d42; // 'BM' WINDOWS_BITMAP_SIGNATURE
hdr.bfSize = (sizeof(BITMAPINFOHEADER_WIN32) + head.biSizeImage + GetPaletteSize()) + 14 ; // GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/;
hdr.bfReserved1 = hdr.bfReserved2 = 0;
hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + sizeof(BITMAPINFOHEADER_WIN32) + GetPaletteSize();
hdr.bfType = m_ntohs(hdr.bfType);
hdr.bfSize = m_ntohl(hdr.bfSize);
hdr.bfOffBits = m_ntohl(hdr.bfOffBits);
BITMAPINFOHEADER_WIN32 headBMP;
headBMP.biSize = sizeof(BITMAPINFOHEADER_WIN32);
headBMP.biBitCount = head.biBitCount;
headBMP.biClrImportant = head.biClrImportant;
headBMP.biClrUsed = head.biClrUsed;
headBMP.biCompression = head.biCompression;
headBMP.biHeight = head.biHeight;
headBMP.biPlanes = head.biPlanes;
headBMP.biSizeImage = head.biSizeImage;
headBMP.biWidth = head.biWidth;
headBMP.biXPelsPerMeter = head.biXPelsPerMeter;
headBMP.biYPelsPerMeter = head.biYPelsPerMeter;
// Write the file header
int nFileHeadLen = min(14,sizeof(hdr));
hFile->Write(&hdr,nFileHeadLen,1);
//copy attributes
memcpy(pDib,&headBMP,sizeof(BITMAPINFOHEADER_WIN32));
bihtoh((BITMAPINFOHEADER_WIN32*)pDib);
// Write the DIB header and the pixels
if(nImgType == CXIMAGE_FORMAT_JPG)
{
int nBmpInfoHeaderLen = sizeof(BITMAPINFOHEADER_WIN32);
hFile->Write(pDib,nBmpInfoHeaderLen,1);
int nJpgInfoHeaderLen = sizeof(BITMAPINFOHEADER);
int nBodyLen = GetPaletteSize() + headBMP.biSizeImage ;
hFile->Write(pDib+nJpgInfoHeaderLen,nBodyLen,1);
}else
{
int nBodyLen = sizeof(BITMAPINFOHEADER_WIN32) + GetPaletteSize() + headBMP.biSizeImage ;
hFile->Write(pDib,nBodyLen,1);
}
bihtoh((BITMAPINFOHEADER_WIN32*)pDib);
这仅仅是核心部分代码,其它代码有需要的请自行魔改!
鉴于项目需要,仅支持JPG转BMP的,其它格式的还需要自行支持。