Fix Issue1: Add insert_image() function
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
TARGET = image
|
||||
|
||||
#include(../../../src/xlsx/qtxlsx.pri)
|
||||
QT += xlsx
|
||||
|
||||
SOURCES += main.cpp
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <QtGui>
|
||||
#include "xlsxworkbook.h"
|
||||
#include "xlsxworksheet.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
# define DATA_PATH "../../../"
|
||||
#else
|
||||
# define DATA_PATH "./"
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
QGuiApplication(argc, argv);
|
||||
|
||||
QXlsx::Workbook workbook;
|
||||
QXlsx::Worksheet *sheet = workbook.addWorksheet();
|
||||
QImage image(400, 300, QImage::Format_RGB32);
|
||||
image.fill(Qt::green);
|
||||
sheet->insertImage(5, 5, image);
|
||||
|
||||
workbook.save(DATA_PATH"Test.xlsx");
|
||||
// workbook.save(DATA_PATH"Test2.zip");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = hello style \
|
||||
documentproperty
|
||||
documentproperty \
|
||||
image
|
||||
|
||||
|
||||
+4
-2
@@ -21,7 +21,8 @@ HEADERS += $$PWD/xlsxdocpropscore_p.h \
|
||||
$$PWD/xlsxworkbook_p.h \
|
||||
$$PWD/xlsxworksheet_p.h \
|
||||
$$PWD/xlsxformat_p.h \
|
||||
$$PWD/xlsxglobal.h
|
||||
$$PWD/xlsxglobal.h \
|
||||
$$PWD/xlsxdrawing_p.h
|
||||
|
||||
SOURCES += $$PWD/xlsxdocpropscore.cpp \
|
||||
$$PWD/xlsxdocpropsapp.cpp \
|
||||
@@ -36,4 +37,5 @@ SOURCES += $$PWD/xlsxdocpropscore.cpp \
|
||||
$$PWD/xlsxworkbook.cpp \
|
||||
$$PWD/xlsxworksheet.cpp \
|
||||
$$PWD/xlsxzipwriter.cpp \
|
||||
$$PWD/xlsxpackage.cpp
|
||||
$$PWD/xlsxpackage.cpp \
|
||||
$$PWD/xlsxdrawing.cpp
|
||||
|
||||
@@ -64,6 +64,11 @@ void ContentTypes::addChartsheetName(const QString &name)
|
||||
addOverride(QStringLiteral("/xl/chartsheets/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.chartsheet+xml"));
|
||||
}
|
||||
|
||||
void ContentTypes::addDrawingName(const QString &name)
|
||||
{
|
||||
addOverride(QStringLiteral("/xl/drawings/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawing+xml"));
|
||||
}
|
||||
|
||||
void ContentTypes::addChartName(const QString &name)
|
||||
{
|
||||
addOverride(QStringLiteral("/xl/charts/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawingml.chart+xml"));
|
||||
@@ -77,7 +82,7 @@ void ContentTypes::addCommentName(const QString &name)
|
||||
void ContentTypes::addImageTypes(const QStringList &imageTypes)
|
||||
{
|
||||
foreach (QString type, imageTypes)
|
||||
addOverride(type, QStringLiteral("image/") + type);
|
||||
addDefault(type, QStringLiteral("image/") + type);
|
||||
}
|
||||
|
||||
void ContentTypes::addTableName(const QString &name)
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#include "xlsxdrawing_p.h"
|
||||
#include "xlsxxmlwriter_p.h"
|
||||
|
||||
namespace QXlsx {
|
||||
|
||||
Drawing::Drawing(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
embedded = false;
|
||||
orientation = 0;
|
||||
}
|
||||
|
||||
void Drawing::saveToXmlFile(QIODevice *device)
|
||||
{
|
||||
XmlStreamWriter writer(device);
|
||||
|
||||
writer.writeStartDocument(QStringLiteral("1.0"), true);
|
||||
writer.writeStartElement(QStringLiteral("xdr:wsDr"));
|
||||
writer.writeAttribute(QStringLiteral("xmlns:xdr"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"));
|
||||
writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main"));
|
||||
|
||||
if (embedded) {
|
||||
int index = 1;
|
||||
foreach (XlsxDrawingDimensionData *dimension, dimensionList) {
|
||||
writeTwoCellAnchor(writer, index, dimension);
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
//write the xdr:absoluteAnchor element
|
||||
writeAbsoluteAnchor(writer, 1);
|
||||
}
|
||||
|
||||
writer.writeEndElement();//xdr:wsDr
|
||||
writer.writeEndDocument();
|
||||
}
|
||||
|
||||
void Drawing::writeTwoCellAnchor(XmlStreamWriter &writer, int index, XlsxDrawingDimensionData *data)
|
||||
{
|
||||
writer.writeStartElement(QStringLiteral("xdr:twoCellAnchor"));
|
||||
if (data->drawing_type == 2)
|
||||
writer.writeAttribute(QStringLiteral("editAs"), QStringLiteral("oneCell"));
|
||||
// if (shape)
|
||||
// writer.writeAttribute(QStringLiteral("editAs"), );
|
||||
|
||||
writer.writeStartElement(QStringLiteral("xdr:from"));
|
||||
writer.writeTextElement(QStringLiteral("xdr:col"), QString::number(data->col_from));
|
||||
writer.writeTextElement(QStringLiteral("xdr:colOff"), QString::number((int)data->col_from_offset));
|
||||
writer.writeTextElement(QStringLiteral("xdr:row"), QString::number(data->row_from));
|
||||
writer.writeTextElement(QStringLiteral("xdr:rowOff"), QString::number((int)data->row_from_offset));
|
||||
writer.writeEndElement(); //xdr:from
|
||||
|
||||
writer.writeStartElement(QStringLiteral("xdr:to"));
|
||||
writer.writeTextElement(QStringLiteral("xdr:col"), QString::number(data->col_to));
|
||||
writer.writeTextElement(QStringLiteral("xdr:colOff"), QString::number((int)data->col_to_offset));
|
||||
writer.writeTextElement(QStringLiteral("xdr:row"), QString::number(data->row_to));
|
||||
writer.writeTextElement(QStringLiteral("xdr:rowOff"), QString::number((int)data->row_to_offset));
|
||||
writer.writeEndElement(); //xdr:to
|
||||
|
||||
if (data->drawing_type == 1) {
|
||||
//Graphics frame, xdr:graphicFrame
|
||||
writeGraphicFrame(writer, index, data->description);
|
||||
} else if (data->drawing_type == 2) {
|
||||
//Image, xdr:pic
|
||||
writePicture(writer, index, data->col_absolute, data->row_absolute, data->width, data->height, data->description);
|
||||
} else {
|
||||
//Shape, xdr:sp
|
||||
}
|
||||
|
||||
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
|
||||
writer.writeEndElement(); //xdr:twoCellAnchor
|
||||
}
|
||||
|
||||
void Drawing::writeAbsoluteAnchor(XmlStreamWriter &writer, int index)
|
||||
{
|
||||
writer.writeStartElement(QStringLiteral("xdr:absoluteAnchor"));
|
||||
if (orientation == 0) {
|
||||
writePos(writer, 0, 0);
|
||||
writeExt(writer, 9308969, 6078325);
|
||||
} else {
|
||||
writePos(writer, 0, -47625);
|
||||
writeExt(writer, 6162675, 6124575);
|
||||
}
|
||||
|
||||
writeGraphicFrame(writer, index);
|
||||
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
|
||||
|
||||
writer.writeEndElement(); //xdr:absoluteAnchor
|
||||
}
|
||||
|
||||
void Drawing::writePos(XmlStreamWriter &writer, int x, int y)
|
||||
{
|
||||
writer.writeEmptyElement(QStringLiteral("xdr:pos"));
|
||||
writer.writeAttribute(QStringLiteral("x"), QString::number(x));
|
||||
writer.writeAttribute(QStringLiteral("y"), QString::number(y));
|
||||
}
|
||||
|
||||
void Drawing::writeExt(XmlStreamWriter &writer, int cx, int cy)
|
||||
{
|
||||
writer.writeStartElement(QStringLiteral("xdr:ext"));
|
||||
writer.writeAttribute(QStringLiteral("cx"), QString::number(cx));
|
||||
writer.writeAttribute(QStringLiteral("cy"), QString::number(cy));
|
||||
}
|
||||
|
||||
void Drawing::writeGraphicFrame(XmlStreamWriter &writer, int index, const QString &name)
|
||||
{
|
||||
writer.writeStartElement(QStringLiteral("xdr:graphicFrame"));
|
||||
writer.writeAttribute(QStringLiteral("macro"), QString());
|
||||
|
||||
writer.writeStartElement(QStringLiteral("xdr:nvGraphicFramePr"));
|
||||
writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
|
||||
writer.writeAttribute(QStringLiteral("id"), QString::number(index+1));
|
||||
writer.writeAttribute(QStringLiteral("name"), name.isEmpty() ? QStringLiteral("Chart%1").arg(index): name);
|
||||
if (embedded) {
|
||||
writer.writeEmptyElement(QStringLiteral("xdr:cNvGraphicFramePr"));
|
||||
} else {
|
||||
writer.writeStartElement(QStringLiteral("xdr:cNvGraphicFramePr"));
|
||||
writer.writeEmptyElement(QStringLiteral("a:graphicFrameLocks"));
|
||||
writer.writeAttribute(QStringLiteral("noGrp"), QStringLiteral("1"));
|
||||
writer.writeEndElement(); //xdr:cNvGraphicFramePr
|
||||
}
|
||||
|
||||
writer.writeEndElement();//xdr:nvGraphicFramePr
|
||||
writer.writeEndElement(); //xdr:graphicFrame
|
||||
}
|
||||
|
||||
void Drawing::writePicture(XmlStreamWriter &writer, int index, double col_abs, double row_abs, int width, int height, const QString &description)
|
||||
{
|
||||
writer.writeStartElement(QStringLiteral("xdr:pic"));
|
||||
|
||||
writer.writeStartElement(QStringLiteral("xdr:nvPicPr"));
|
||||
writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
|
||||
writer.writeAttribute(QStringLiteral("id"), QString::number(index+1));
|
||||
writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Picture%1").arg(index));
|
||||
if (!description.isEmpty())
|
||||
writer.writeAttribute(QStringLiteral("descr"), description);
|
||||
|
||||
writer.writeStartElement(QStringLiteral("xdr:cNvPicPr"));
|
||||
writer.writeEmptyElement(QStringLiteral("a:picLocks"));
|
||||
writer.writeAttribute(QStringLiteral("noChangeAspect"), QStringLiteral("1"));
|
||||
writer.writeEndElement(); //xdr:cNvPicPr
|
||||
|
||||
writer.writeEndElement(); //xdr:nvPicPr
|
||||
|
||||
writer.writeStartElement(QStringLiteral("xdr:blipFill"));
|
||||
writer.writeEmptyElement(QStringLiteral("a:blip"));
|
||||
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
|
||||
writer.writeAttribute(QStringLiteral("r:embed"), QStringLiteral("rId%1").arg(index));
|
||||
writer.writeStartElement(QStringLiteral("a:stretch"));
|
||||
writer.writeEmptyElement(QStringLiteral("a:fillRect"));
|
||||
writer.writeEndElement(); //a:stretch
|
||||
writer.writeEndElement();//xdr:blipFill
|
||||
|
||||
writer.writeStartElement(QStringLiteral("xdr:spPr"));
|
||||
|
||||
writer.writeStartElement(QStringLiteral("a:xfrm"));
|
||||
writer.writeEmptyElement(QStringLiteral("a:off"));
|
||||
writer.writeAttribute(QStringLiteral("x"), QString::number((int)col_abs));
|
||||
writer.writeAttribute(QStringLiteral("y"), QString::number((int)row_abs));
|
||||
writer.writeEmptyElement(QStringLiteral("a:ext"));
|
||||
writer.writeAttribute(QStringLiteral("cx"), QString::number(width));
|
||||
writer.writeAttribute(QStringLiteral("cy"), QString::number(height));
|
||||
writer.writeEndElement(); //a:xfrm
|
||||
|
||||
writer.writeStartElement(QStringLiteral("a:prstGeom"));
|
||||
writer.writeAttribute(QStringLiteral("prst"), QStringLiteral("rect"));
|
||||
writer.writeEmptyElement(QStringLiteral("a:avLst"));
|
||||
writer.writeEndElement(); //a:prstGeom
|
||||
|
||||
writer.writeEndElement(); //xdr:spPr
|
||||
|
||||
writer.writeEndElement(); //xdr:pic
|
||||
}
|
||||
|
||||
} // namespace QXlsx
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef QXLSX_DRAWING_H
|
||||
#define QXLSX_DRAWING_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
namespace QXlsx {
|
||||
class XmlStreamWriter;
|
||||
|
||||
struct XlsxDrawingDimensionData
|
||||
{
|
||||
int drawing_type;
|
||||
int col_from;
|
||||
int row_from;
|
||||
double col_from_offset;
|
||||
double row_from_offset;
|
||||
int col_to;
|
||||
int row_to;
|
||||
double col_to_offset;
|
||||
double row_to_offset;
|
||||
int col_absolute;
|
||||
int row_absolute;
|
||||
int width;
|
||||
int height;
|
||||
QString description;
|
||||
int shape;
|
||||
};
|
||||
|
||||
class Drawing : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Drawing(QObject *parent = 0);
|
||||
void saveToXmlFile(QIODevice *device);
|
||||
|
||||
bool embedded;
|
||||
int orientation;
|
||||
QList <XlsxDrawingDimensionData *> dimensionList;
|
||||
|
||||
private:
|
||||
void writeTwoCellAnchor(XmlStreamWriter &writer, int index, XlsxDrawingDimensionData *data);
|
||||
void writeAbsoluteAnchor(XmlStreamWriter &writer, int index);
|
||||
void writePos(XmlStreamWriter &writer, int x, int y);
|
||||
void writeExt(XmlStreamWriter &writer, int cx, int cy);
|
||||
void writeGraphicFrame(XmlStreamWriter &writer, int index, const QString &name=QString());
|
||||
void writePicture(XmlStreamWriter &writer, int index, double col_abs, double row_abs, int width, int height, const QString &description);
|
||||
};
|
||||
|
||||
} // namespace QXlsx
|
||||
|
||||
#endif // QXLSX_DRAWING_H
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "xlsxstyles_p.h"
|
||||
#include "xlsxrelationships_p.h"
|
||||
#include "xlsxzipwriter_p.h"
|
||||
#include "xlsxdrawing_p.h"
|
||||
#include <QBuffer>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -93,11 +94,13 @@ bool Package::createPackage(const QString &packageName)
|
||||
return false;
|
||||
|
||||
m_workbook->styles()->clearExtraFormatInfo(); //These info will be generated when write the worksheet data.
|
||||
m_workbook->prepareDrawings();
|
||||
|
||||
writeWorksheetFiles(zipWriter);
|
||||
// writeChartsheetFiles(zipWriter);
|
||||
writeWorkbookFile(zipWriter);
|
||||
// writeChartFiles(zipWriter);
|
||||
// writeDrawingFiles(zipWriter);
|
||||
writeDrawingFiles(zipWriter);
|
||||
// writeVmlFiles(zipWriter);
|
||||
// writeCommentFiles(zipWriter);
|
||||
// writeTableFiles(zipWriter);
|
||||
@@ -110,9 +113,10 @@ bool Package::createPackage(const QString &packageName)
|
||||
writeThemeFile(zipWriter);
|
||||
writeRootRelsFile(zipWriter);
|
||||
writeWorkbookRelsFile(zipWriter);
|
||||
writeWorksheetRelsFile(zipWriter);
|
||||
writeWorksheetRelsFiles(zipWriter);
|
||||
// writeChartsheetRelsFile(zipWriter);
|
||||
// writeImageFiles(zipWriter);
|
||||
writeDrawingRelsFiles(zipWriter);
|
||||
writeImageFiles(zipWriter);
|
||||
// writeVbaProjectFiles(zipWriter);
|
||||
|
||||
zipWriter.close();
|
||||
@@ -144,6 +148,19 @@ void Package::writeWorkbookFile(ZipWriter &zipWriter)
|
||||
zipWriter.addFile(QStringLiteral("xl/workbook.xml"), data);
|
||||
}
|
||||
|
||||
void Package::writeDrawingFiles(ZipWriter &zipWriter)
|
||||
{
|
||||
for (int i=0; i<m_workbook->drawings().size(); ++i) {
|
||||
Drawing *drawing = m_workbook->drawings()[i];
|
||||
|
||||
QByteArray data;
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
drawing->saveToXmlFile(&buffer);
|
||||
zipWriter.addFile(QStringLiteral("xl/drawings/drawing%1.xml").arg(i+1), data);
|
||||
}
|
||||
}
|
||||
|
||||
void Package::writeContentTypesFiles(ZipWriter &zipWriter)
|
||||
{
|
||||
ContentTypes content;
|
||||
@@ -158,6 +175,15 @@ void Package::writeContentTypesFiles(ZipWriter &zipWriter)
|
||||
}
|
||||
}
|
||||
|
||||
int drawing_index = 1;
|
||||
foreach (Drawing *drawing, m_workbook->drawings()) {
|
||||
content.addDrawingName(QStringLiteral("drawing%1").arg(drawing_index));
|
||||
drawing_index += 1;
|
||||
}
|
||||
|
||||
if (!m_workbook->images().isEmpty())
|
||||
content.addImageTypes(QStringList()<<QStringLiteral("png"));
|
||||
|
||||
if (m_workbook->sharedStrings()->count())
|
||||
content.addSharedString();
|
||||
|
||||
@@ -283,7 +309,7 @@ void Package::writeWorkbookRelsFile(ZipWriter &zipWriter)
|
||||
zipWriter.addFile(QStringLiteral("xl/_rels/workbook.xml.rels"), data);
|
||||
}
|
||||
|
||||
void Package::writeWorksheetRelsFile(ZipWriter &zipWriter)
|
||||
void Package::writeWorksheetRelsFiles(ZipWriter &zipWriter)
|
||||
{
|
||||
int index = 1;
|
||||
foreach (Worksheet *sheet, m_workbook->worksheets()) {
|
||||
@@ -293,7 +319,8 @@ void Package::writeWorksheetRelsFile(ZipWriter &zipWriter)
|
||||
|
||||
foreach (QString link, sheet->externUrlList())
|
||||
rels.addWorksheetRelationship(QStringLiteral("/hyperlink"), link, QStringLiteral("External"));
|
||||
|
||||
foreach (QString link, sheet->externDrawingList())
|
||||
rels.addWorksheetRelationship(QStringLiteral("/drawing"), link);
|
||||
QByteArray data;
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
@@ -302,4 +329,39 @@ void Package::writeWorksheetRelsFile(ZipWriter &zipWriter)
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Package::writeDrawingRelsFiles(ZipWriter &zipWriter)
|
||||
{
|
||||
int index = 1;
|
||||
foreach (Worksheet *sheet, m_workbook->worksheets()) {
|
||||
if (sheet->drawingLinks().size() == 0)
|
||||
continue;
|
||||
Relationships rels;
|
||||
|
||||
typedef QPair<QString, QString> PairType;
|
||||
foreach (PairType pair, sheet->drawingLinks())
|
||||
rels.addDocumentRelationship(pair.first, pair.second);
|
||||
|
||||
QByteArray data;
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
rels.saveToXmlFile(&buffer);
|
||||
zipWriter.addFile(QStringLiteral("xl/drawings/_rels/drawing%1.xml.rels").arg(index), data);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Package::writeImageFiles(ZipWriter &zipWriter)
|
||||
{
|
||||
for (int i=0; i<m_workbook->images().size(); ++i) {
|
||||
QImage image = m_workbook->images()[i];
|
||||
|
||||
QByteArray data;
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
image.save(&buffer, "png");
|
||||
zipWriter.addFile(QStringLiteral("xl/media/image%1.png").arg(i+1), data);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QXlsx
|
||||
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
// void writeChartsheetFiles(ZipWriter &zipWriter);
|
||||
void writeWorkbookFile(ZipWriter &zipWriter);
|
||||
// void writeChartFiles(ZipWriter &zipWriter);
|
||||
// void writeDrawingFiles(ZipWriter &zipWriter);
|
||||
void writeDrawingFiles(ZipWriter &zipWriter);
|
||||
// void writeVmlFiles(ZipWriter &zipWriter);
|
||||
// void writeCommentFiles(ZipWriter &zipWriter);
|
||||
// void writeTableFiles(ZipWriter &zipWriter);
|
||||
@@ -56,9 +56,10 @@ private:
|
||||
void writeThemeFile(ZipWriter &zipWriter);
|
||||
void writeRootRelsFile(ZipWriter &zipWriter);
|
||||
void writeWorkbookRelsFile(ZipWriter &zipWriter);
|
||||
void writeWorksheetRelsFile(ZipWriter &zipWriter);
|
||||
void writeWorksheetRelsFiles(ZipWriter &zipWriter);
|
||||
// void writeChartsheetRelsFile(ZipWriter &zipWriter);
|
||||
// void writeImageFiles(ZipWriter &zipWriter);
|
||||
void writeDrawingRelsFiles(ZipWriter &zipWriter);
|
||||
void writeImageFiles(ZipWriter &zipWriter);
|
||||
// void writeVbaProjectFiles(ZipWriter &zipWriter);
|
||||
|
||||
Workbook * m_workbook;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "xlsxformat.h"
|
||||
#include "xlsxpackage_p.h"
|
||||
#include "xlsxxmlwriter_p.h"
|
||||
#include "xlsxworksheet_p.h"
|
||||
|
||||
namespace QXlsx {
|
||||
|
||||
@@ -221,6 +222,44 @@ Styles *Workbook::styles()
|
||||
return d->styles;
|
||||
}
|
||||
|
||||
QList<QImage> Workbook::images()
|
||||
{
|
||||
Q_D(Workbook);
|
||||
return d->images;
|
||||
}
|
||||
|
||||
QList<Drawing *> Workbook::drawings()
|
||||
{
|
||||
Q_D(Workbook);
|
||||
return d->drawings;
|
||||
}
|
||||
|
||||
void Workbook::prepareDrawings()
|
||||
{
|
||||
Q_D(Workbook);
|
||||
int drawing_id = 0;
|
||||
int image_ref_id = 0;
|
||||
d->images.clear();
|
||||
d->drawings.clear();
|
||||
|
||||
foreach (Worksheet *sheet, d->worksheets) {
|
||||
if (sheet->images().isEmpty()) //No drawing (such as Image, ...)
|
||||
continue;
|
||||
|
||||
sheet->clearExtraDrawingInfo();
|
||||
|
||||
//At present, only picture type supported
|
||||
drawing_id += 1;
|
||||
for (int idx = 0; idx < sheet->images().size(); ++idx) {
|
||||
image_ref_id += 1;
|
||||
sheet->prepareImage(idx, image_ref_id, drawing_id);
|
||||
d->images.append(sheet->images()[idx]->image);
|
||||
}
|
||||
|
||||
d->drawings.append(sheet->drawing());
|
||||
}
|
||||
}
|
||||
|
||||
void Workbook::saveToXmlFile(QIODevice *device)
|
||||
{
|
||||
Q_D(Workbook);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "xlsxglobal.h"
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QImage>
|
||||
class QIODevice;
|
||||
|
||||
namespace QXlsx {
|
||||
@@ -37,6 +38,7 @@ class Format;
|
||||
class SharedStrings;
|
||||
class Styles;
|
||||
class Package;
|
||||
class Drawing;
|
||||
|
||||
class WorkbookPrivate;
|
||||
class Q_XLSX_EXPORT Workbook : public QObject
|
||||
@@ -73,6 +75,9 @@ private:
|
||||
|
||||
SharedStrings *sharedStrings();
|
||||
Styles *styles();
|
||||
QList<QImage> images();
|
||||
QList<Drawing *> drawings();
|
||||
void prepareDrawings();
|
||||
void saveToXmlFile(QIODevice *device);
|
||||
|
||||
WorkbookPrivate * const d_ptr;
|
||||
|
||||
@@ -39,6 +39,8 @@ public:
|
||||
SharedStrings *sharedStrings;
|
||||
QList<Worksheet *> worksheets;
|
||||
Styles *styles;
|
||||
QList<QImage> images;
|
||||
QList<Drawing *> drawings;
|
||||
|
||||
bool strings_to_numbers_enabled;
|
||||
bool date1904;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "xlsxutility_p.h"
|
||||
#include "xlsxsharedstrings_p.h"
|
||||
#include "xlsxxmlwriter_p.h"
|
||||
#include "xlsxdrawing_p.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <QDateTime>
|
||||
@@ -45,6 +46,8 @@ namespace QXlsx {
|
||||
WorksheetPrivate::WorksheetPrivate(Worksheet *p) :
|
||||
q_ptr(p)
|
||||
{
|
||||
drawing = 0;
|
||||
|
||||
xls_rowmax = 1048576;
|
||||
xls_colmax = 16384;
|
||||
xls_strmax = 32767;
|
||||
@@ -264,6 +267,18 @@ QStringList Worksheet::externUrlList() const
|
||||
return d->externUrlList;
|
||||
}
|
||||
|
||||
QStringList Worksheet::externDrawingList() const
|
||||
{
|
||||
Q_D(const Worksheet);
|
||||
return d->externDrawingList;
|
||||
}
|
||||
|
||||
QList<QPair<QString, QString> > Worksheet::drawingLinks() const
|
||||
{
|
||||
Q_D(const Worksheet);
|
||||
return d->drawingLinks;
|
||||
}
|
||||
|
||||
int Worksheet::write(int row, int column, const QVariant &value, Format *format)
|
||||
{
|
||||
Q_D(Worksheet);
|
||||
@@ -461,6 +476,14 @@ int Worksheet::writeUrl(int row, int column, const QUrl &url, Format *format, co
|
||||
return error;
|
||||
}
|
||||
|
||||
int Worksheet::insertImage(int row, int column, const QImage &image, const QPointF &offset, double xScale, double yScale)
|
||||
{
|
||||
Q_D(Worksheet);
|
||||
|
||||
d->imageList.append(new XlsxImageData(row, column, image, offset, xScale, yScale));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Worksheet::saveToXmlFile(QIODevice *device)
|
||||
{
|
||||
Q_D(Worksheet);
|
||||
@@ -533,6 +556,7 @@ void Worksheet::saveToXmlFile(QIODevice *device)
|
||||
writer.writeEndElement();//sheetData
|
||||
|
||||
d->writeHyperlinks(writer);
|
||||
d->writeDrawings(writer);
|
||||
|
||||
writer.writeEndElement();//worksheet
|
||||
writer.writeEndDocument();
|
||||
@@ -681,6 +705,13 @@ void WorksheetPrivate::writeHyperlinks(XmlStreamWriter &writer)
|
||||
writer.writeEndElement();//hyperlinks
|
||||
}
|
||||
|
||||
void WorksheetPrivate::writeDrawings(XmlStreamWriter &writer)
|
||||
{
|
||||
int index = externUrlList.size() + 1;
|
||||
writer.writeEmptyElement(QStringLiteral("drawing"));
|
||||
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(index));
|
||||
}
|
||||
|
||||
/*
|
||||
Sets row height and format. Row height measured in point size. If format
|
||||
equals 0 then format is ignored.
|
||||
@@ -729,4 +760,192 @@ bool Worksheet::setColumn(int colFirst, int colLast, double width, Format *forma
|
||||
return true;
|
||||
}
|
||||
|
||||
Drawing *Worksheet::drawing() const
|
||||
{
|
||||
Q_D(const Worksheet);
|
||||
return d->drawing;
|
||||
}
|
||||
|
||||
QList<XlsxImageData *> Worksheet::images() const
|
||||
{
|
||||
Q_D(const Worksheet);
|
||||
return d->imageList;
|
||||
}
|
||||
|
||||
void Worksheet::clearExtraDrawingInfo()
|
||||
{
|
||||
Q_D(Worksheet);
|
||||
if (d->drawing) {
|
||||
delete d->drawing;
|
||||
d->drawing = 0;
|
||||
d->externDrawingList.clear();
|
||||
d->drawingLinks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Worksheet::prepareImage(int index, int image_id, int drawing_id)
|
||||
{
|
||||
Q_D(Worksheet);
|
||||
if (!d->drawing) {
|
||||
d->drawing = new Drawing(this);
|
||||
d->drawing->embedded = true;
|
||||
d->externDrawingList.append(QStringLiteral("../drawings/drawing%1.xml").arg(drawing_id));
|
||||
}
|
||||
|
||||
XlsxImageData *imageData = d->imageList[index];
|
||||
|
||||
XlsxDrawingDimensionData *data = new XlsxDrawingDimensionData;
|
||||
data->drawing_type = 2;
|
||||
|
||||
double width = imageData->image.width() * imageData->xScale;
|
||||
double height = imageData->image.height() * imageData->yScale;
|
||||
|
||||
XlsxObjectPositionData posData = d->pixelsToEMUs(d->objectPixelsPosition(imageData->col, imageData->row, imageData->offset.x(), imageData->offset.y(), width, height));
|
||||
data->col_from = posData.col_start;
|
||||
data->col_from_offset = posData.x1;
|
||||
data->row_from = posData.row_start;
|
||||
data->row_from_offset = posData.y1;
|
||||
data->col_to = posData.col_end;
|
||||
data->col_to_offset = posData.x2;
|
||||
data->row_to = posData.row_end;
|
||||
data->row_to_offset = posData.y2;
|
||||
data->width = posData.width;
|
||||
data->height = posData.height;
|
||||
data->col_absolute = posData.x_abs;
|
||||
data->row_absolute = posData.y_abs;
|
||||
|
||||
d->drawing->dimensionList.append(data);
|
||||
|
||||
d->drawingLinks.append(QPair<QString, QString>(QStringLiteral("/image"), QStringLiteral("../media/image%1.png").arg(image_id)));
|
||||
}
|
||||
|
||||
/*
|
||||
Convert the height of a cell from user's units to pixels. If the
|
||||
height hasn't been set by the user we use the default value. If
|
||||
the row is hidden it has a value of zero.
|
||||
*/
|
||||
int WorksheetPrivate::rowPixelsSize(int row)
|
||||
{
|
||||
double height;
|
||||
if (row_sizes.contains(row))
|
||||
height = row_sizes[row];
|
||||
else
|
||||
height = default_row_height;
|
||||
return static_cast<int>(4.0 / 3.0 *height);
|
||||
}
|
||||
|
||||
/*
|
||||
Convert the width of a cell from user's units to pixels. Excel rounds
|
||||
the column width to the nearest pixel. If the width hasn't been set
|
||||
by the user we use the default value. If the column is hidden it
|
||||
has a value of zero.
|
||||
*/
|
||||
int WorksheetPrivate::colPixelsSize(int col)
|
||||
{
|
||||
double max_digit_width = 7.0; //For Calabri 11
|
||||
double padding = 5.0;
|
||||
int pixels = 0;
|
||||
|
||||
if (col_sizes.contains(col)) {
|
||||
double width = col_sizes[col];
|
||||
if (width < 1)
|
||||
pixels = static_cast<int>(width * (max_digit_width + padding) + 0.5);
|
||||
else
|
||||
pixels = static_cast<int>(width * max_digit_width + 0.5) + padding;
|
||||
} else {
|
||||
pixels = 64;
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
/*
|
||||
col_start Col containing upper left corner of object.
|
||||
x1 Distance to left side of object.
|
||||
row_start Row containing top left corner of object.
|
||||
y1 Distance to top of object.
|
||||
col_end Col containing lower right corner of object.
|
||||
x2 Distance to right side of object.
|
||||
row_end Row containing bottom right corner of object.
|
||||
y2 Distance to bottom of object.
|
||||
width Width of object frame.
|
||||
height Height of object frame.
|
||||
x_abs Absolute distance to left side of object.
|
||||
y_abs Absolute distance to top side of object.
|
||||
*/
|
||||
XlsxObjectPositionData WorksheetPrivate::objectPixelsPosition(int col_start, int row_start, double x1, double y1, double width, double height)
|
||||
{
|
||||
double x_abs = 0;
|
||||
double y_abs = 0;
|
||||
for (int col_id = 1; col_id < col_start; ++col_id)
|
||||
x_abs += colPixelsSize(col_id);
|
||||
x_abs += x1;
|
||||
for (int row_id = 1; row_id < row_start; ++row_id)
|
||||
y_abs += rowPixelsSize(row_id);
|
||||
y_abs += y1;
|
||||
|
||||
// Adjust start column for offsets that are greater than the col width.
|
||||
while (x1 > colPixelsSize(col_start)) {
|
||||
x1 -= colPixelsSize(col_start);
|
||||
col_start += 1;
|
||||
}
|
||||
while (y1 > rowPixelsSize(row_start)) {
|
||||
y1 -= rowPixelsSize(row_start);
|
||||
row_start += 1;
|
||||
}
|
||||
|
||||
int col_end = col_start;
|
||||
int row_end = row_start;
|
||||
double x2 = width + x1;
|
||||
double y2 = height + y1;
|
||||
|
||||
while (x2 > colPixelsSize(col_end)) {
|
||||
x2 -= colPixelsSize(col_end);
|
||||
col_end += 1;
|
||||
}
|
||||
|
||||
while (y2 > rowPixelsSize(row_end)) {
|
||||
y2 -= rowPixelsSize(row_end);
|
||||
row_end += 1;
|
||||
}
|
||||
|
||||
XlsxObjectPositionData data;
|
||||
data.col_start = col_start;
|
||||
data.x1 = x1;
|
||||
data.row_start = row_start;
|
||||
data.y1 = y1;
|
||||
data.col_end = col_end;
|
||||
data.x2 = x2;
|
||||
data.row_end = row_end;
|
||||
data.y2 = y2;
|
||||
data.x_abs = x_abs;
|
||||
data.y_abs = y_abs;
|
||||
data.width = width;
|
||||
data.height = height;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate the vertices that define the position of a graphical
|
||||
object within the worksheet in EMUs.
|
||||
|
||||
The vertices are expressed as English Metric Units (EMUs). There are
|
||||
12,700 EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per
|
||||
pixel
|
||||
*/
|
||||
XlsxObjectPositionData WorksheetPrivate::pixelsToEMUs(const XlsxObjectPositionData &data)
|
||||
{
|
||||
XlsxObjectPositionData result = data;
|
||||
result.x1 = static_cast<int>(data.x1 * 9525 + 0.5);
|
||||
result.y1 = static_cast<int>(data.y1 * 9525 + 0.5);
|
||||
result.x2 = static_cast<int>(data.x2 * 9525 + 0.5);
|
||||
result.y2 = static_cast<int>(data.y2 * 9525 + 0.5);
|
||||
result.x_abs = static_cast<int>(data.x_abs * 9525 + 0.5);
|
||||
result.y_abs = static_cast<int>(data.y_abs * 9525 + 0.5);
|
||||
result.width = static_cast<int>(data.width * 9525 + 0.5);
|
||||
result.height = static_cast<int>(data.height * 9525 + 0.5);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} //namespace
|
||||
|
||||
@@ -30,15 +30,19 @@
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QPointF>
|
||||
class QIODevice;
|
||||
class QDateTime;
|
||||
class QUrl;
|
||||
class QImage;
|
||||
|
||||
namespace QXlsx {
|
||||
class Package;
|
||||
class Workbook;
|
||||
class XmlStreamWriter;
|
||||
class Format;
|
||||
class Drawing;
|
||||
struct XlsxImageData;
|
||||
|
||||
class WorksheetPrivate;
|
||||
class Q_XLSX_EXPORT Worksheet : public QObject
|
||||
@@ -56,6 +60,8 @@ public:
|
||||
int writeDateTime(int row, int column, const QDateTime& dt, Format *format=0);
|
||||
int writeUrl(int row, int column, const QUrl &url, Format *format=0, const QString &display=QString(), const QString &tip=QString());
|
||||
|
||||
int insertImage(int row, int column, const QImage &image, const QPointF &offset=QPointF(), double xScale=1, double yScale=1);
|
||||
|
||||
bool setRow(int row, double height, Format* format=0, bool hidden=false);
|
||||
bool setColumn(int colFirst, int colLast, double width, Format* format=0, bool hidden=false);
|
||||
|
||||
@@ -76,6 +82,12 @@ private:
|
||||
void setSelected(bool select);
|
||||
void saveToXmlFile(QIODevice *device);
|
||||
QStringList externUrlList() const;
|
||||
QStringList externDrawingList() const;
|
||||
QList<QPair<QString, QString> > drawingLinks() const;
|
||||
Drawing *drawing() const;
|
||||
QList<XlsxImageData *> images() const;
|
||||
void prepareImage(int index, int image_id, int drawing_id);
|
||||
void clearExtraDrawingInfo();
|
||||
|
||||
WorksheetPrivate * const d_ptr;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#define XLSXWORKSHEET_P_H
|
||||
#include "xlsxworksheet.h"
|
||||
|
||||
#include <QImage>
|
||||
|
||||
namespace QXlsx {
|
||||
|
||||
struct XlsxCellData
|
||||
@@ -65,6 +67,67 @@ struct XlsxUrlData
|
||||
QString tip;
|
||||
};
|
||||
|
||||
struct XlsxImageData
|
||||
{
|
||||
XlsxImageData(int row, int col, const QImage &image, const QPointF &offset, double xScale, double yScale) :
|
||||
row(row), col(col), image(image), offset(offset), xScale(xScale), yScale(yScale)
|
||||
{
|
||||
}
|
||||
|
||||
int row;
|
||||
int col;
|
||||
QImage image;
|
||||
QPointF offset;
|
||||
double xScale;
|
||||
double yScale;
|
||||
};
|
||||
|
||||
/*
|
||||
The vertices that define the position of a graphical object
|
||||
within the worksheet in pixels.
|
||||
|
||||
+------------+------------+
|
||||
| A | B |
|
||||
+-----+------------+------------+
|
||||
| |(x1,y1) | |
|
||||
| 1 |(A1)._______|______ |
|
||||
| | | | |
|
||||
| | | | |
|
||||
+-----+----| OBJECT |-----+
|
||||
| | | | |
|
||||
| 2 | |______________. |
|
||||
| | | (B2)|
|
||||
| | | (x2,y2)|
|
||||
+---- +------------+------------+
|
||||
|
||||
Example of an object that covers some of the area from cell A1 to B2.
|
||||
|
||||
Based on the width and height of the object we need to calculate 8 vars:
|
||||
|
||||
col_start, row_start, col_end, row_end, x1, y1, x2, y2.
|
||||
|
||||
We also calculate the absolute x and y position of the top left vertex of
|
||||
the object. This is required for images.
|
||||
|
||||
The width and height of the cells that the object occupies can be
|
||||
variable and have to be taken into account.
|
||||
*/
|
||||
struct XlsxObjectPositionData
|
||||
{
|
||||
int col_start;
|
||||
double x1;
|
||||
int row_start;
|
||||
double y1;
|
||||
int col_end;
|
||||
double x2;
|
||||
int row_end;
|
||||
double y2;
|
||||
double width;
|
||||
double height;
|
||||
double x_abs;
|
||||
double y_abs;
|
||||
};
|
||||
|
||||
struct XlsxRowInfo
|
||||
{
|
||||
XlsxRowInfo(double height, Format *format, bool hidden) :
|
||||
@@ -104,15 +167,24 @@ public:
|
||||
void writeSheetData(XmlStreamWriter &writer);
|
||||
void writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCellData *cell);
|
||||
void writeHyperlinks(XmlStreamWriter &writer);
|
||||
void writeDrawings(XmlStreamWriter &writer);
|
||||
int rowPixelsSize(int row);
|
||||
int colPixelsSize(int col);
|
||||
XlsxObjectPositionData objectPixelsPosition(int col_start, int row_start, double x1, double y1, double width, double height);
|
||||
XlsxObjectPositionData pixelsToEMUs(const XlsxObjectPositionData &data);
|
||||
|
||||
Workbook *workbook;
|
||||
Drawing *drawing;
|
||||
QMap<int, QMap<int, XlsxCellData *> > cellTable;
|
||||
QMap<int, QMap<int, QString> > comments;
|
||||
QMap<int, QMap<int, XlsxUrlData *> > urlTable;
|
||||
QStringList externUrlList;
|
||||
QStringList externDrawingList;
|
||||
QList<XlsxImageData *> imageList;
|
||||
QMap<int, XlsxRowInfo *> rowsInfo;
|
||||
QList<XlsxColumnInfo *> colsInfo;
|
||||
QMap<int, XlsxColumnInfo *> colsInfoHelper;//Not owns the XlsxColumnInfo
|
||||
QList<QPair<QString, QString> > drawingLinks;
|
||||
|
||||
int xls_rowmax;
|
||||
int xls_colmax;
|
||||
@@ -124,6 +196,8 @@ public:
|
||||
int previous_row;
|
||||
|
||||
QMap<int, QString> row_spans;
|
||||
QMap<int, double> row_sizes;
|
||||
QMap<int, double> col_sizes;
|
||||
|
||||
int outline_row_level;
|
||||
int outline_col_level;
|
||||
|
||||
Reference in New Issue
Block a user