Merge branch 'master' of https://github.com/xournalpp/xournalpp.git
commit
9b1dc75a3f
12 changed files with 481 additions and 156 deletions
@ -0,0 +1,215 @@ |
||||
#include "ImageExport.h" |
||||
|
||||
#include "control/jobs/ProgressListener.h" |
||||
#include "model/Document.h" |
||||
#include "view/PdfView.h" |
||||
|
||||
#include <cairo-svg.h> |
||||
#include <i18n.h> |
||||
|
||||
|
||||
ImageExport::ImageExport(Document* doc, Path filename, ExportGraphicsFormat format, bool hideBackground, PageRangeVector& exportRange) |
||||
: doc(doc), |
||||
filename(filename), |
||||
format(format), |
||||
hideBackground(hideBackground), |
||||
exportRange(exportRange) |
||||
{ |
||||
XOJ_INIT_TYPE(ImageExport); |
||||
} |
||||
|
||||
ImageExport::~ImageExport() |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
XOJ_RELEASE_TYPE(ImageExport); |
||||
} |
||||
|
||||
/**
|
||||
* PNG dpi |
||||
*/ |
||||
void ImageExport::setPngDpi(int dpi) |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
this->pngDpi = dpi; |
||||
} |
||||
|
||||
/**
|
||||
* @return the last error message to show to the user |
||||
*/ |
||||
string ImageExport::getLastErrorMsg() |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
return lastError; |
||||
} |
||||
|
||||
/**
|
||||
* Create surface |
||||
*/ |
||||
void ImageExport::createSurface(double width, double height, int id) |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
if (format == EXPORT_GRAPHICS_PNG) |
||||
{ |
||||
this->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, |
||||
width * this->pngDpi / 72.0, |
||||
height * this->pngDpi / 72.0); |
||||
this->cr = cairo_create(this->surface); |
||||
double factor = this->pngDpi / 72.0; |
||||
cairo_scale(this->cr, factor, factor); |
||||
} |
||||
else if (format == EXPORT_GRAPHICS_SVG) |
||||
{ |
||||
string filepath = getFilenameWithNumber(id); |
||||
this->surface = cairo_svg_surface_create(filepath.c_str(), width, height); |
||||
cairo_svg_surface_restrict_to_version(this->surface, CAIRO_SVG_VERSION_1_2); |
||||
this->cr = cairo_create(this->surface); |
||||
} |
||||
else |
||||
{ |
||||
g_error("Unsupported graphics format: %i", format); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Free / store the surface |
||||
*/ |
||||
bool ImageExport::freeSurface(int id) |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
cairo_destroy(this->cr); |
||||
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS; |
||||
if (format == EXPORT_GRAPHICS_PNG) |
||||
{ |
||||
string filepath = getFilenameWithNumber(id); |
||||
status = cairo_surface_write_to_png(surface, filepath.c_str()); |
||||
} |
||||
cairo_surface_destroy(surface); |
||||
|
||||
// we ignore this problem
|
||||
if (status != CAIRO_STATUS_SUCCESS) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/**
|
||||
* Get a filename with a number, e.g. .../export-1.png, if the no is -1, return .../export.png |
||||
*/ |
||||
string ImageExport::getFilenameWithNumber(int no) |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
if (no == -1) |
||||
{ |
||||
// No number to add
|
||||
return filename.str(); |
||||
} |
||||
|
||||
string filepath = filename.str(); |
||||
size_t dotPos = filepath.find_last_of("."); |
||||
if (dotPos == string::npos) |
||||
{ |
||||
// No file extension, add number
|
||||
return filepath + "-" + std::to_string(no); |
||||
} |
||||
|
||||
return filepath.substr(0, dotPos) + "-" + std::to_string(no) + filepath.substr(dotPos); |
||||
} |
||||
|
||||
/**
|
||||
* Export a single PNG page |
||||
*/ |
||||
void ImageExport::exportImagePage(int pageId, int id, double zoom, ExportGraphicsFormat format, DocumentView& view) |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
doc->lock(); |
||||
PageRef page = doc->getPage(pageId); |
||||
doc->unlock(); |
||||
|
||||
createSurface(page->getWidth(), page->getHeight(), id); |
||||
|
||||
cairo_status_t state = cairo_surface_status(this->surface); |
||||
if (state != CAIRO_STATUS_SUCCESS) |
||||
{ |
||||
this->lastError = _("Error save image #1"); |
||||
return; |
||||
} |
||||
|
||||
if (page->getBackgroundType().isPdfPage()) |
||||
{ |
||||
int pgNo = page->getPdfPageNr(); |
||||
XojPdfPageSPtr popplerPage = doc->getPdfPage(pgNo); |
||||
|
||||
PdfView::drawPage(NULL, popplerPage, cr, zoom, page->getWidth(), page->getHeight()); |
||||
} |
||||
|
||||
view.drawPage(page, this->cr, true, hideBackground); |
||||
|
||||
if (!freeSurface(id)) |
||||
{ |
||||
// could not create this file...
|
||||
this->lastError = _("Error save image #2"); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Create one Graphics file per page |
||||
*/ |
||||
void ImageExport::exportGraphics(ProgressListener* stateListener) |
||||
{ |
||||
XOJ_CHECK_TYPE(ImageExport); |
||||
|
||||
// don't lock the page here for the whole flow, else we get a dead lock...
|
||||
// the ui is blocked, so there should be no changes...
|
||||
int count = doc->getPageCount(); |
||||
|
||||
bool onePage = ((this->exportRange.size() == 1) && (this->exportRange[0]->getFirst() == this->exportRange[0]->getLast())); |
||||
|
||||
char selectedPages[count]; |
||||
int selectedCount = 0; |
||||
for (int i = 0; i < count; i++) |
||||
{ |
||||
selectedPages[i] = 0; |
||||
} |
||||
for (PageRangeEntry* e : this->exportRange) |
||||
{ |
||||
for (int x = e->getFirst(); x <= e->getLast(); x++) |
||||
{ |
||||
selectedPages[x] = 1; |
||||
selectedCount++; |
||||
} |
||||
} |
||||
|
||||
stateListener->setMaximumState(selectedCount); |
||||
|
||||
DocumentView view; |
||||
double zoom = this->pngDpi / 72.0; |
||||
int current = 0; |
||||
|
||||
for (int i = 0; i < count; i++) |
||||
{ |
||||
int id = i + 1; |
||||
if (onePage) |
||||
{ |
||||
id = -1; |
||||
} |
||||
|
||||
if (selectedPages[i]) |
||||
{ |
||||
stateListener->setCurrentState(current++); |
||||
|
||||
exportImagePage(i, id, zoom, format, view); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,122 @@ |
||||
/*
|
||||
* Xournal++ |
||||
* |
||||
* Image export implementation |
||||
* |
||||
* @author Xournal++ Team |
||||
* https://github.com/xournalpp/xournalpp
|
||||
* |
||||
* @license GNU GPLv2 or later |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include "view/DocumentView.h" |
||||
|
||||
#include <PageRange.h> |
||||
#include <Path.h> |
||||
#include <XournalType.h> |
||||
|
||||
#include <gtk/gtk.h> |
||||
|
||||
class Document; |
||||
class ProgressListener; |
||||
|
||||
enum ExportGraphicsFormat { |
||||
EXPORT_GRAPHICS_UNDEFINED, |
||||
EXPORT_GRAPHICS_PDF, |
||||
EXPORT_GRAPHICS_PNG, |
||||
EXPORT_GRAPHICS_SVG |
||||
}; |
||||
|
||||
class ImageExport |
||||
{ |
||||
public: |
||||
ImageExport(Document* doc, Path filename, ExportGraphicsFormat format, bool hideBackground, PageRangeVector& exportRange); |
||||
virtual ~ImageExport(); |
||||
|
||||
public: |
||||
/**
|
||||
* PNG dpi |
||||
*/ |
||||
void setPngDpi(int dpi); |
||||
|
||||
/**
|
||||
* @return The last error message to show to the user |
||||
*/ |
||||
string getLastErrorMsg(); |
||||
|
||||
/**
|
||||
* Create one Graphics file per page |
||||
*/ |
||||
void exportGraphics(ProgressListener* stateListener); |
||||
|
||||
private: |
||||
/**
|
||||
* Create surface |
||||
*/ |
||||
void createSurface(double width, double height, int id); |
||||
|
||||
/**
|
||||
* Free / store the surface |
||||
*/ |
||||
bool freeSurface(int id); |
||||
|
||||
/**
|
||||
* Get a filename with a number, e.g. .../export-1.png, if the no is -1, return .../export.png |
||||
*/ |
||||
string getFilenameWithNumber(int no); |
||||
|
||||
/**
|
||||
* Export a single Image page |
||||
*/ |
||||
void exportImagePage(int pageId, int id, double zoom, ExportGraphicsFormat format, DocumentView& view); |
||||
|
||||
public: |
||||
XOJ_TYPE_ATTRIB; |
||||
|
||||
/**
|
||||
* Document to export |
||||
*/ |
||||
Document* doc = NULL; |
||||
|
||||
/**
|
||||
* Filename for export |
||||
*/ |
||||
Path filename; |
||||
|
||||
/**
|
||||
* Export graphics format |
||||
*/ |
||||
ExportGraphicsFormat format = EXPORT_GRAPHICS_UNDEFINED; |
||||
|
||||
/**
|
||||
* Do not export the Background |
||||
*/ |
||||
bool hideBackground = false; |
||||
|
||||
/**
|
||||
* The range to export |
||||
*/ |
||||
PageRangeVector& exportRange; |
||||
|
||||
/**
|
||||
* PNG dpi |
||||
*/ |
||||
int pngDpi = 300; |
||||
|
||||
/**
|
||||
* Export surface |
||||
*/ |
||||
cairo_surface_t* surface = NULL; |
||||
|
||||
/**
|
||||
* Cairo context |
||||
*/ |
||||
cairo_t* cr = NULL; |
||||
|
||||
/**
|
||||
* The last error message to show to the user |
||||
*/ |
||||
string lastError; |
||||
}; |
||||
Loading…
Reference in new issue