QtXlsx读写.xlsx的图片

QtXlsx读写.xlsx的图片

先介绍一下.xlsx 的图片保存的xml文件。解压.xlsx文件后,在 /xl/drawings 目录下有对应sheet的图片.xml文件统一叫 drawingX.xml

[html]  view plain  copy
  1. <xdr:wsDr>  
  2. <xdr:twoCellAnchor editAs="oneCell">  
  3. <xdr:from>  
  4. <xdr:col>2</xdr:col>  
  5. <xdr:colOff>0</xdr:colOff>  
  6. <xdr:row>2</xdr:row>  
  7. <xdr:rowOff>165100</xdr:rowOff>  
  8. </xdr:from>  
  9. <xdr:to>  
  10. <xdr:col>4</xdr:col>  
  11. <xdr:colOff>671830</xdr:colOff>  
  12. <xdr:row>8</xdr:row>  
  13. <xdr:rowOff>154305</xdr:rowOff>  
  14. </xdr:to>  
  15. <xdr:pic>  
  16. <xdr:nvPicPr>  
  17. <xdr:cNvPr id="2" name="图片 1" descr="image1"/>  
  18. <xdr:cNvPicPr>  
  19. <a:picLocks noChangeAspect="1"/>  
  20. </xdr:cNvPicPr>  
  21. </xdr:nvPicPr>  
  22. <xdr:blipFill>  
  23. <a:blip r:embed="rId1"/>  
  24. <a:srcRect/>  
  25. <a:stretch>  
  26. <a:fillRect/>  
  27. </a:stretch>  
  28. </xdr:blipFill>  
  29. <xdr:spPr>  
  30. <a:xfrm>  
  31. <a:off x="1371600" y="527050"/>  
  32. <a:ext cx="1662430" cy="1017905"/>  
  33. </a:xfrm>  
  34. <a:prstGeom prst="rect">  
  35. <a:avLst/>  
  36. </a:prstGeom>  
  37. </xdr:spPr>  
  38. </xdr:pic>  
  39. <xdr:clientData/>  
  40. </xdr:twoCellAnchor>  
  41. </xdr:wsDr>  
比如这个是我的某一个drawing1.xml文件,其中xdr:twoCellAnchor表示了确定图片位置的方式,.xlsx 共有3中方式,除了前面的还有OneCellAnchor和AbsoluteAnchor。

xdr:from 和 xdr:to 分别是这个twoCellAnchor的两个位置参数。明显,这个twoCellAnchor表示图片位置由两个单元格的位置确认,同理OneCell由一个确定,而AbsoluteAnchor则直接给定坐标

form 和to 标签下有col ,row还有对应的rowoff和coloff是对应的偏移量,现在回过头来看QXlsx

QXlsx写入图片

 QXlsx只给了一个插入图片的方法

[cpp]  view plain  copy
  1. bool Document::insertImage(int row, int column, const QImage &image)  

这个方法非常简单粗糙,继续看里面的内容

[cpp]  view plain  copy
  1. bool Worksheet::insertImage(int row, int column, const QImage &image)  
  2. {  
  3.     Q_D(Worksheet);  
  4.   
  5.     if (image.isNull())  
  6.         return false;  
  7.   
  8.     if (!d->drawing)  
  9.         d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));  
  10.   
  11.     DrawingOneCellAnchor *anchor = new DrawingOneCellAnchor(d->drawing.data(), DrawingAnchor::Picture);  
  12.   
  13.     /* 
  14.         The size are expressed as English Metric Units (EMUs). There are 
  15.         12,700 EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per 
  16.         pixel 
  17.     */  
  18.     anchor->from = XlsxMarker(row, column, 0, 0);//rowoff 和 coloff 直接给的0  
  19.     anchor->ext = QSize(image.width() * 9525, image.height() * 9525);  
  20.   
  21.     anchor->setObjectPicture(image);  
  22.     return true;  
  23. }  

实际上只插入了一张 OneCellAnchor的图片,连rowoff 和coloff都直接填的0,这样应该很难满足我们的要求的

[cpp]  view plain  copy
  1. class DrawingAbsoluteAnchor : public DrawingAnchor  
  2. {  
  3. public:  
  4.     DrawingAbsoluteAnchor(Drawing *drawing, ObjectType objectType=Unknown);  
  5.   
  6.     QPoint pos;  
  7.     QSize ext;  
  8.   
  9.     bool loadFromXml(QXmlStreamReader &reader);  
  10.     void saveToXml(QXmlStreamWriter &writer) const;  
  11. };  
  12.   
  13. class DrawingOneCellAnchor : public DrawingAnchor  
  14. {  
  15. public:  
  16.     DrawingOneCellAnchor(Drawing *drawing, ObjectType objectType=Unknown);  
  17.   
  18.     XlsxMarker from;  
  19.     QSize ext;  
  20.   
  21.     bool loadFromXml(QXmlStreamReader &reader);  
  22.     void saveToXml(QXmlStreamWriter &writer) const;  
  23. };  
  24.   
  25. class DrawingTwoCellAnchor : public DrawingAnchor  
  26. {  
  27. public:  
  28.     DrawingTwoCellAnchor(Drawing *drawing, ObjectType objectType=Unknown);  
  29.   
  30.     XlsxMarker from;  
  31.     XlsxMarker to;  
  32.   
  33.     bool loadFromXml(QXmlStreamReader &reader);  
  34.     void saveToXml(QXmlStreamWriter &writer) const;  
  35. };  
  36.   
  37. }   

实际上 QXlsx 已经完全定义好了这三种格式的图片,功能都已经完成了,真正有需要的话,可以自己仿照他的方法把剩下的两种写好

2015-12-28 编辑

自行添加了三种方法,在xlsxworksheet.h头文件中,可以参考一下

[cpp]  view plain  copy
  1. bool insertImage(XlsxMarker star_cell, QSize size,const QImage &image);  
  2. bool insertImage(XlsxMarker star_cell, XlsxMarker end_cell,const QImage &image);  
  3. bool insertImage(QPoint star,QSize size, const QImage &image);  

分别对应 onecell  、twocell 以及 absolute

[cpp]  view plain  copy
  1. bool Worksheet::insertImage(XlsxMarker star_cell, QSize size, const QImage &image)  
  2. {  
  3.     Q_D(Worksheet);  
  4.   
  5.     if (image.isNull())  
  6.         return false;  
  7.   
  8.     if (!d->drawing)  
  9.         d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));  
  10.     DrawingOneCellAnchor *anchor = new DrawingOneCellAnchor(d->drawing.data(), DrawingAnchor::Picture);  
  11.     anchor->from = XlsxMarker(star_cell.row(), star_cell.col(), star_cell.rowOff()*9525, star_cell.colOff()*9525);  
  12.     anchor->ext = QSize(size.width() * 9525, size.height() * 9525);  
  13.   
  14.     anchor->setObjectPicture(image);  
  15.     return true;  
  16.   
  17. }  
  18.   
  19. bool Worksheet::insertImage(XlsxMarker star_cell, XlsxMarker end_cell, const QImage &image)  
  20. {  
  21.     Q_D(Worksheet);  
  22.   
  23.     if (image.isNull())  
  24.         return false;  
  25.   
  26.     if (!d->drawing)  
  27.         d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));  
  28.     DrawingTwoCellAnchor *anchor = new DrawingTwoCellAnchor(d->drawing.data(), DrawingAnchor::Picture);  
  29.     anchor->from = XlsxMarker(star_cell.row(), star_cell.col(), star_cell.rowOff()*9525, star_cell.colOff()*9525);  
  30.     anchor->to = XlsxMarker(end_cell.row(), end_cell.col(), end_cell.rowOff()*9525, end_cell.colOff()*9525);  
  31.   
  32.     anchor->setObjectPicture(image);  
  33.     return true;  
  34.   
  35. }  
  36.   
  37. bool Worksheet::insertImage(QPoint star, QSize size, const QImage &image)  
  38. {  
  39.     Q_D(Worksheet);  
  40.   
  41.     if (image.isNull())  
  42.         return false;  
  43.   
  44.     if (!d->drawing)  
  45.         d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));  
  46.     DrawingAbsoluteAnchor *anchor = new DrawingAbsoluteAnchor(d->drawing.data(), DrawingAnchor::Picture);  
  47.     anchor->pos=star*9525;  
  48.     anchor->ext=size*9525;  
  49.     anchor->setObjectPicture(image);  
  50.     return true;  
  51.   
  52. }  

这里传入的都是对应的界面值,也就是 pix 单位的参数,所以存入的参数都乘以了 9525 需要注意一下


QXlsx读取图片

        读取图片,QXlsx完全就没有提供接口,只能靠自己完成了。实际上,QXlsx已经读取了图片信息

[cpp]  view plain  copy
  1. for (int i=0; i<workbook->drawings().size(); ++i) {  
  2.     Drawing *drawing = workbook->drawings()[i];  
  3.     QString rel_path = getRelFilePath(drawing->filePath());  
  4.     if (zipReader.filePaths().contains(rel_path))  
  5.         drawing->relationships()->loadFromXmlData(zipReader.fileData(rel_path));  
  6.     drawing->loadFromXmlData(zipReader.fileData(drawing->filePath()));  
  7. }  

    所以,稍微修改源码,我们也能提取到里面的图片
[cpp]  view plain  copy
  1.    foreach(QString sheetName,xls_doc->sheetNames())  
  2.    {  
  3.        Worksheet *sheet = static_cast<Worksheet *>(xls_doc->sheet(sheetName));  
  4.        if(sheet)  
  5.        {  
  6.            Drawing *drawing = sheet->drawing();  
  7.            if(drawing)  
  8.            {  
  9.                qDebug()<<drawing->anchors.count();  
  10.                for(int j=0;j<drawing->anchors.count();j++)  
  11.                {  
  12.                    DrawingAnchor *my_anchor=drawing->anchors.at(j);  
  13.                    MediaFile* m_mediafile=my_anchor->m_pictureFile.data();  
  14.                    QImage image;  
  15.                    QByteArray contents=m_mediafile->m_contents;  
  16.                    
  17.                    if(my_anchor->DrawingName=="DrawingTwoCellAnchor")  
  18.                    {  
  19.                        DrawingTwoCellAnchor* cellanchor=static_cast<DrawingTwoCellAnchor*>(my_anchor);  
  20.                        //                            qDebug()<<cellanchor->from.cell<<cellanchor->from.offset/9525;  
  21.                        //                            qDebug()<<cellanchor->to.cell<<cellanchor->to.offset/9525;  
  22.                         
  23.                    }  
  24.                    if(my_anchor->DrawingName=="DrawingOneCellAnchor")  
  25.                    {  
  26.                        DrawingOneCellAnchor* cellanchor=static_cast<DrawingOneCellAnchor*>(my_anchor);  
  27.                    }  
  28.                    if(my_anchor->DrawingName=="DrawingAbsoluteAnchor")  
  29.                    {  
  30.                        DrawingAbsoluteAnchor* cellanchor=static_cast<DrawingAbsoluteAnchor*>(my_anchor);  
  31.                    }  
  32.   
  33.                     
  34.                }  
  35.   
  36.            }  
  37.   
  38.     }  
  39. }  
        
sheet->drawing();是一个私有的方法,需要在源码中修改一下。

这里我为了分清3中派生的类自己添加了一个 DrawingName

sheet 下面的drawing 有个一个叫 anchors 的QList 

[cpp]  view plain  copy
  1. class Drawing : public AbstractOOXmlFile  
  2. {  
  3. public:  
  4.     Drawing(AbstractSheet *sheet, CreateFlag flag);  
  5.     ~Drawing();  
  6.     void saveToXmlFile(QIODevice *device) const;  
  7.     bool loadFromXmlFile(QIODevice *device);  
  8.   
  9.     AbstractSheet *sheet;  
  10.     Workbook *workbook;  
  11.     QList<DrawingAnchor *> anchors;  
  12. };  
我们需要的就是从DrawingAnchor *中得到

[cpp]  view plain  copy
  1. QSharedPointer<MediaFile> m_pictureFile;  

[cpp]  view plain  copy
  1. QByteArray MediaFile::contents() const  
  2. {  
  3.     return m_contents;  
  4. }  

这就是我们需要的图片信息了

[cpp]  view plain  copy
  1. new_image=QImage::fromData(cellanchor->m_pictureFile.data()->contents());  

这样就可以得到我们需要的图片,而位置信息可以自行从上述的3个类中寻找
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值