I have a mouse area which I grab and save into image after click on it.
MouseArea {
id: mouseArea
objectName: "testMouseArea"
width: 64;
height: 64
onPressed: tile.grabToImage(function (result) {
result.saveToFile("D:/ouput.png")
});
Rectangle {
id: tile
anchors.fill: parent
color: "blue"
}
}
Before saving I want to change opacity of grabbed image of the mouse area.
I've added
result.image.opacity = 0.5
before saving, but it doesn't help. Output files have the same opacity (no effect at all).
Ok, the best way is to set opacity to the saved Item and then grab the image. If for some reason you want to do more with the image so that all about QImage processing. You can create custom C++ item, probably singleton, or regular QML item with appropriate method:
bool ImageProcess::saveWithOpacity(const QImage &input, const QString &path, double opacity)
{
QImage image(input.size(), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter p(&image);
p.setOpacity(opacity);
p.drawImage(0, 0, input);
p.end();
return image.save(path);
}
and then you can use that in QML code:
MouseArea {
id: area
...
onClicked: {
area.grabToImage(function (result) {
imgProcess.saveWithOpacity(result.image, "/path/to/file/img.png", 0.5);
});
}
...
}
Related
I'm using QQuickImageProvider to pass 3d scanner images from C++ to QML and then use these images as customer texture for model (using qt quick 3d here). I faced a problem that texture blinks getting to black for a second. It repeats quite often.
I used to investigate streaming images as VideoOutput but this approach doesn't suit me as I have to use geometry data of surface and in case of VideoOutput it doesn't allow to map these images on geometry coordinates. Could you advise something in this case?
Below is example of my code.
QML:
Image {
id: textureImage
source: renderControl.sourceUrl
anchors.fill: parent
visible: false // tried with cache true and false both
}
Node {
id: mainScene
DirectionalLight {
position: Qt.vector3d(-500, 500, -100)
ambientColor: Qt.rgba(1.0, 1.0, 1.0, 0.5)
}
Model {
id: viewModel
position: Qt.vector3d(0, 50, 0)
visible: true
scale: Qt.vector3d(10, 11, 4)
geometry: RenderData{ // C++ class which sends url to image provider
id: renderControl
objectName: "geometryData"
}
DefaultMaterial {
id: defaultMaterial
Texture {
id: baseColorMap
sourceItem: textureImage
}
cullMode: DefaultMaterial.NoCulling
diffuseMap: baseColorMap
}
materials: [
defaultMaterial
]
}
C++
.h
class TextureImageProvider : public QObject, public QQuickImageProvider
{
QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override;
Q_SIGNALS:
void imageUpdated(const QUrl& imageUrl);
std::shared_ptr<QImage> textureImage_;
}
class RenderData : public QQuick3DGeometry
{
Q_OBJECT
Q_PROPERTY(QUrl sourceUrl READ sourceUrl WRITE setSourceUrl NOTIFY sourceUrlChanged)
TextureImageProvider* imageProvider_;
}
.cpp
void RenderData::updateData(QImage& textureImage)
{
const QUrl imageUrl = QString("image://texture_image_provider/%1").arg(Uuid::createUuid().toString().c_str());
textureImage_ = std::make_shared<QImage>(image);
Q_EMIT imageUpdated(url);
}
QImage TextureImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
{
return *textureImage_;
}
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
{
engine_->addImageProvider("texture_image_provider", &renderData_-getImageProvider());
}
In QML, I want to specify a list of options (strings) that the user can choose to insert into my backend. But I don't want the list to contain strings that are already in the backend. And if the backend is updated, then the list of options should also update.
First I wrote a subclass QAbstractListModel which exposes a list of QString interface for my backend. It follows the guidelines from the docs, and exposes two custom functions push_back and indexOf.
class MyModel: public QAbstractListModel {
Q_OBJECT
public:
MyModel() { ... } // connect to the backend
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override {
Q_UNUSED(role);
if (!hasIndex(index.row(), index.column())) {
return {};
}
return ... // retreive backend object at index.row() and convert to QString
}
Q_INVOKABLE void push_back(const QString& item) {
beginInsertRows(QModelIndex(), int(_data->size()), int(_data->size()));
... // convert QString to backend data type and insert into backend
endInsertRows();
}
Q_INVOKABLE int indexOf(const QString& item) {
return ... // convert QString to backend type, and search backend for this object. return -1 if not found
}
private:
// pointer to backend object
};
I was thinking something like this in my QML. First a view of the strings that are already in the backend. This part works fine.
ListView {
anchors.fill: parent
spacing: 5
model: backend // an instance MyModel interface, passed in from main.cpp
delegate: Rectangle {
height: 25
width: 200
Text { text: model.display}
}
}
And then the list of options that can be added to the backend, which are not already part of the backend. This part doesn't work.
ListView {
anchors.fill: parent
spacing: 5
model: ["option1", "option2", "option3"]
delegate: Rectangle {
visible: backend.indexOf(model.modelData) >= 0
height: 25
width: 200
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked: {
backend.push_back(model.modelData)
}
}
Text { text: model.modelData }
}
}
The problem is, when strings are added to the backend, this list does not refresh. I don't think Qt understands that backend.indexOf needs to be recomputed whenever its modified.
You are correct about the problem. There's no binding that will re-call indexOf. One way to fix it is you could add a Connections object so you can listen for a specific signal and then manually update the visible property:
delegate: Rectangle {
visible: backend.indexOf(model.modelData) >= 0
height: 25
width: 200
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked: {
backend.push_back(model.modelData)
}
}
Text { text: model.modelData }
Connections {
target: backend
onCountChanged: visible = (backend.indexOf(model.modelData) >= 0)
}
}
I am working on BB10 cascades. I am trying to load multiple images from network. I have referred following example and I have modified it to load a single image. Sample code is as follows:
main.qml
import bb.cascades 1.2
Page {
Container {
id: outer
Container {
preferredHeight: 500
preferredWidth: 768
layout: DockLayout {}
onCreationCompleted: {}
// The ActivityIndicator that is only active and visible while the image is loading
ActivityIndicator {
id: activity
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
preferredHeight: 300
visible: _loader.loading
running: _loader.loading
}
// The ImageView that shows the loaded image after loading has finished without error
ImageView {
id: image
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
image: _loader.image
visible: !_loader.loading && _loader.label == ""
}
// The Label that shows a possible error message after loading has finished
Label {
id: lable
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
preferredWidth: 500
visible: !_loader.loading && !_loader.label == ""
text: _loader.label
multiline: true
}
}
Button {
text: "load Image"
onClicked: {
_loader.load();
console.log("loading:::"+_loader.loading);
}
}
}
}
applicatioui.hpp
#ifndef ApplicationUI_HPP_
#define ApplicationUI_HPP_
#include "imageloader.hpp"
#include
namespace bb
{
namespace cascades
{
class LocaleHandler;
}
}
class QTranslator;
class ApplicationUI : public QObject
{
Q_OBJECT
public:
ApplicationUI();
virtual ~ApplicationUI() {}
Q_INVOKABLE void prepareImage();
Q_INVOKABLE void loadImage();
Q_INVOKABLE ImageLoader* getImageloadderInstance();
private slots:
void onSystemLanguageChanged();
private:
ImageLoader* image;
QTranslator* m_pTranslator;
bb::cascades::LocaleHandler* m_pLocaleHandler;
};
#endif /* ApplicationUI_HPP_ */
applicatioui.cpp
#include "applicationui.hpp"
#include
#include
#include
#include
using namespace bb::cascades;
ApplicationUI::ApplicationUI() :
QObject()
{
// prepare the localization
m_pTranslator = new QTranslator(this);
m_pLocaleHandler = new LocaleHandler(this);
image =new ImageLoader("http://uat2.thomascook.in/bpmapp-upload/download/fstore/7f00000105a3d7bf_eb1af9_1485f184f7b_-52f0/GIT_banner.jpg",this);
bool res = QObject::connect(m_pLocaleHandler, SIGNAL(systemLanguageChanged()), this, SLOT(onSystemLanguageChanged()));
// This is only available in Debug builds
Q_ASSERT(res);
// Since the variable is not used in the app, this is added to avoid a
// compiler warning
Q_UNUSED(res);
// initial load
onSystemLanguageChanged();
// Create scene document from main.qml asset, the parent is set
// to ensure the document gets destroyed properly at shut down.
QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
qml->setContextProperty("_loader",this);
// Create root object for the UI
AbstractPane *root = qml->createRootObject();
if(root)
{
}
// Set created root object as the application scene
Application::instance()->setScene(root);
}
void ApplicationUI::onSystemLanguageChanged()
{
QCoreApplication::instance()->removeTranslator(m_pTranslator);
// Initiate, load and install the application translation files.
QString locale_string = QLocale().name();
QString file_name = QString("loading_Image_%1").arg(locale_string);
if (m_pTranslator->load(file_name, "app/native/qm")) {
QCoreApplication::instance()->installTranslator(m_pTranslator);
}
}
ImageLoader* ApplicationUI::getImageloadderInstance()
{
image =new ImageLoader("http://uat2.thomascook.in/bpmapp-upload/download/fstore/7f00000105a3d7bf_eb1af9_1485f184f7b_-52f0/GIT_banner.jpg",this);
return (image);
}
void ApplicationUI::prepareImage()
{
image =new ImageLoader("http://uat2.thomascook.in/bpmapp-upload/download/fstore/7f00000105a3d7bf_eb1af9_1485f184f7b_-52f0/GIT_banner.jpg",this);
}
void ApplicationUI::loadImage()
{
image->load();
}
Now I want to load multiple images. I tried to create QList<QObject*>* image;
and add instances of the ImageLoader class, but I don't know how to access it in main.qml.
Any ideas how to do so?
https://github.com/RileyGB/BlackBerry10-Samples/tree/master/WebImageViewSample
follow this link there is a control called "WebImageView". you just have to set the url of image and its done. int main.qml coder have shown user friendly UI.
thanks to #Bojan Kogoj
I want to write simple Qt Quick app with draggable QQuickItems. The items are well draggeble because of embedded MouseArea in the items. But a problem is that mouse events are not fired into C++ code in virtual overloaded functions. How to solve this problem or maybe there are some examples that I didn't find?
The QML file:
import QtQuick 2.0
import SimpleMaterial 1.0
Rectangle {
width: 320
height: 480
color: "black"
SimpleMaterialItem {
width: parent.width;
height: parent.height / 3;
color: "steelblue"
MouseArea {
anchors.fill: parent
width: 64
height: 64
drag.target: parent
drag.axis: Drag.XandYAxis
}
}
}
The C++ class:
class Item : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
Item()
{
setFlag(ItemHasContents, true);
setFlag(ItemAcceptsDrops, true);
setFlag(ItemAcceptsInputMethod, true);
setAcceptedMouseButtons(Qt::AllButtons);
}
void mousePressEvent(QMouseEvent * event)
{
qDebug("Press"); // NOT CALLED!
}
public:
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
...
}
};
If MouseArea handles mouse event it doesn't pass event to its parent.
You need:
onPressed: {
mouse.accepted = false;
}
in mouse area to let the SimpleMaterialItem handle onPressed event.
How can I save QML Image into phone memory ??
also if saving the image was applicable , I have this case which I need to add some text to the image (we can imagine it as we have a transparent image[that hold the text] and put it over the second image , so finally we have one image that we can save it into phone memory)
Not from Image directly. QDeclarativeImage has pixmap, setPixmap and pixmapChange methods, but for some reason there is no property declared. So you cannot use it fom qml. Unfortunately it cannot be used from C++ either - it is a private calsss.
What you can do is paint graphics item to your pixmap and save it to file.
class Capturer : public QObject
{
Q_OBJECT
public:
explicit Capturer(QObject *parent = 0);
Q_INVOKABLE void save(QDeclarativeItem *obj);
};
void Capturer::save(QDeclarativeItem *item)
{
QPixmap pix(item->width(), item->height());
QPainter painter(&pix);
QStyleOptionGraphicsItem option;
item->paint(&painter, &option, NULL);
pix.save("/path/to/output.png");
}
Register "capturer" context variable:
int main()
{
// ...
Capturer capturer;
QmlApplicationViewer viewer;
viewer.rootContext()->setContextProperty("capturer", &capturer);
// ...
}
And use it in your qml:
Rectangle {
// ...
Image {
id: img
source: "/path/to/your/source"
}
MouseArea {
anchors.fill: parent
onClicked: {
capturer.save(img)
}
}
}
With Qt 5.4+ you can do it straight from your Qml with:
grabToImage