From e29c0c1814182f2c711350514b5d633762ec9d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Gur=C3=ADn?= Date: Sun, 29 Sep 2019 02:03:48 -0300 Subject: [PATCH] qpixmap save() --- docs/api/QPixmap.md | 13 +++++ .../nodegui/QtGui/QPixmap/qpixmap_wrap.h | 1 + src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp | 19 +++++++ src/demo.ts | 52 ++++++++++++++----- src/index.ts | 2 +- src/lib/QtGui/QPixmap/index.ts | 9 +++- 6 files changed, 80 insertions(+), 16 deletions(-) diff --git a/docs/api/QPixmap.md b/docs/api/QPixmap.md index 814842165..bae202f52 100644 --- a/docs/api/QPixmap.md +++ b/docs/api/QPixmap.md @@ -42,6 +42,19 @@ returns true if load was successful otherwise returns false. - `imageUrl` string (_optional_). Absolute path of the image that needs to be loaded in the memory. +#### `pixMap.save(fileName, format)` + +Saves the pixmap to the file with the given fileName using the specified image file format and quality factor. Returns `true` if successful; otherwise returns false. + +The quality factor must be in the range `[0,100]` or -1. Specify 0 to obtain small compressed files, 100 for large uncompressed files, and -1 to use the default settings. + +If format is 0, an image format will be chosen from fileName's suffix. + +See also [Reading and Writing Image Files.](https://doc.qt.io/qt-5/qpixmap.html#reading-and-writing-image-files). + +- `fileName` string. +- `format` string. (_optional_). + #### `pixMap.scaled(width, height, aspectRatioMode?)` Scales the pixmap to provided height and width with respect to aspectRatioMode. diff --git a/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h b/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h index 2ba3371c0..31b276f5f 100644 --- a/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h +++ b/src/cpp/include/nodegui/QtGui/QPixmap/qpixmap_wrap.h @@ -16,6 +16,7 @@ public: QPixmap* getInternalInstance(); // Wrapped methods Napi::Value load(const Napi::CallbackInfo& info); + Napi::Value save(const Napi::CallbackInfo& info); Napi::Value scaled(const Napi::CallbackInfo& info); }; diff --git a/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp b/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp index a3d506774..39162c86a 100644 --- a/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp +++ b/src/cpp/lib/QtGui/QPixmap/qpixmap_wrap.cpp @@ -10,6 +10,7 @@ Napi::Object QPixmapWrap::init(Napi::Env env, Napi::Object exports) char CLASSNAME[] = "QPixmap"; Napi::Function func = DefineClass(env, CLASSNAME,{ InstanceMethod("load", &QPixmapWrap::load), + InstanceMethod("save", &QPixmapWrap::save), InstanceMethod("scaled",&QPixmapWrap::scaled), COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE }); @@ -62,6 +63,24 @@ Napi::Value QPixmapWrap::load(const Napi::CallbackInfo& info) return Napi::Boolean::New(env, loadSuccess); } +Napi::Value QPixmapWrap::save(const Napi::CallbackInfo& info) +{ + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + bool loadSuccess = false; + if(info.Length() >= 1 && info.Length() <=3) { + QString fileName = QString::fromUtf8(info[0].As().Utf8Value().c_str()); + if(info.Length() >= 2) { + loadSuccess = this->instance->save(fileName, info[1].As().Utf8Value().c_str()); + } else { + loadSuccess = this->instance->save(fileName); + } + }else { + Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException(); + } + return Napi::Boolean::New(env, loadSuccess); +} + Napi::Value QPixmapWrap::scaled(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); diff --git a/src/demo.ts b/src/demo.ts index acaf607c2..dbbee54cd 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -20,9 +20,13 @@ import { QTextOptionWrapMode, QCheckBoxEvents, QSystemTrayIcon, + ReadWriteImageFormats, + QPushButtonEvents } from "./index"; +import { ok, equal } from "assert"; +import { existsSync, unlinkSync, readFileSync } from "fs"; +import { resolve } from "path" -const path = require("path"); const win = new QMainWindow(); @@ -40,9 +44,9 @@ const checkbox = new QCheckBox(); checkbox.setText("Check me out?"); checkbox.setObjectName("check"); checkbox.setChecked(true); -checkbox.addEventListener(QCheckBoxEvents.toggled, () => { - console.log("checkbox was toggled!"); - label1.setInlineStyle("color: green;"); +checkbox.addEventListener(QCheckBoxEvents.toggled, checked => { + console.log(`${checked ? 'checked' : 'unchecked'}`); + label1.setInlineStyle(`color: ${checked ? 'green' : 'red'}`); }); const dial = new QDial(); @@ -57,11 +61,11 @@ button.setText("Push Push Push!"); button.setObjectName("btn"); const nodeguiLogo = new QIcon( - path.resolve(__dirname, "../extras/assets/nodegui.png") + resolve(__dirname, "../extras/assets/nodegui.png") ); const icon = new QIcon( - path.resolve(__dirname, "../extras/assets/start_icon.png") + resolve(__dirname, "../extras/assets/start_icon.png") ); button.setIcon(icon); @@ -101,13 +105,32 @@ scrollArea.setInlineStyle("flex: 1; width:'100%';"); const imageLabel = new QLabel(); const pixmap = new QPixmap( - path.resolve(__dirname, "../extras/assets/kitchen.png") + resolve(__dirname, "../extras/assets/kitchen.png") ); imageLabel.setPixmap(pixmap); scrollArea.setWidget(imageLabel); +function testQPixmapSave(fileName: string, format?: ReadWriteImageFormats) { + try { + existsSync(fileName) && unlinkSync(fileName); + ok(!existsSync(fileName)); + equal(pixmap.save(fileName, format), true); + ok(existsSync(fileName)); + // ideally we want to use file-type, jimp or magica to verify tmp.png has the correct encoding and/or is identical to source img. + ok(readFileSync(fileName).byteLength > 1000); + } catch (error) { + console.error("QPixmap.save test failed", error, error.stack); + } finally { + unlinkSync(fileName); + } +} +testQPixmapSave("tmp.png"); +testQPixmapSave("tmp.jpg"); +testQPixmapSave("tmp_jpg", "JPG"); +testQPixmapSave("tmp_bmp", "BMP"); + const trayIcon = new QIcon( - path.resolve(__dirname, "../extras/assets/nodegui_white.png") + resolve(__dirname, "../extras/assets/nodegui_white.png") ); const tray = new QSystemTrayIcon(); tray.setIcon(trayIcon); @@ -125,6 +148,7 @@ if (rootView.layout) { rootView.layout.addWidget(dial); } +(async ()=>{ win.setCentralWidget(rootView); win.setStyleSheet(` #root { @@ -134,12 +158,12 @@ win.setStyleSheet(` justify-content: 'space-around'; } `); - -win.setWindowIcon(nodeguiLogo); -win.setWindowTitle("NodeGUI Demo"); -win.resize(400, 700); -win.show(); -win.setWindowState(WindowState.WindowActive); + win.setWindowIcon(nodeguiLogo); + await win.setWindowTitle("NodeGUI Demo"); + win.resize(400, 700); + win.show(); + await win.setWindowState(WindowState.WindowActive); +})(); (global as any).win = win; // To prevent win from being garbage collected. (global as any).systemTray = tray; // To prevent system tray from being garbage collected. diff --git a/src/index.ts b/src/index.ts index 8d8736775..bbfb41fc9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import "./lib/core/bootstrap"; export * from "./lib/QtEnums"; // Gui: export { QApplication } from "./lib/QtGui/QApplication"; -export { QPixmap } from "./lib/QtGui/QPixmap"; +export { QPixmap, ReadWriteImageFormats, ImageFormats } from "./lib/QtGui/QPixmap"; export { QIcon, QIconMode, QIconState } from "./lib/QtGui/QIcon"; export { QCursor } from "./lib/QtGui/QCursor"; export { QTextOptionWrapMode } from "./lib/QtGui/QTextOption"; diff --git a/src/lib/QtGui/QPixmap/index.ts b/src/lib/QtGui/QPixmap/index.ts index 821bebbe5..3d33508f1 100644 --- a/src/lib/QtGui/QPixmap/index.ts +++ b/src/lib/QtGui/QPixmap/index.ts @@ -3,6 +3,9 @@ import { Component, NativeElement } from "../../core/Component"; import { AspectRatioMode } from "../../QtEnums"; import { checkIfNativeElement } from "../../utils/helpers"; +export type ImageFormats = 'BMP' | 'GIF' | 'JPG' | 'JPEG' | 'PNG' | 'PBM' | 'PGM' | 'PPM' | 'XBM' | 'XPM' +export type ReadWriteImageFormats = 'BMP' | 'JPG' | 'JPEG' | 'PNG' | 'PBM' | 'XBM' | 'XPM' + type arg = string | NativeElement; export class QPixmap extends Component { native: NativeElement; @@ -17,9 +20,13 @@ export class QPixmap extends Component { this.native = new addon.QPixmap(); } } - load = (imageUrl: string) => { + load = (imageUrl: string): boolean => { return this.native.load(imageUrl); }; + save = (fileName: string, format?: ReadWriteImageFormats): boolean => { + //TODO: quality argument + return format ? this.native.save(fileName, format) : this.native.save(fileName); + }; scaled = ( width: number, height: number,