diff --git a/plugin.xml b/plugin.xml index f441c6e..fda60c6 100644 --- a/plugin.xml +++ b/plugin.xml @@ -67,6 +67,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ubuntu/CaptureWidget.qml b/src/ubuntu/CaptureWidget.qml new file mode 100644 index 0000000..e3fe20e --- /dev/null +++ b/src/ubuntu/CaptureWidget.qml @@ -0,0 +1,119 @@ +/* + * + * Copyright 2013 Canonical Ltd. + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ +import QtQuick 2.0 +import QtMultimedia 5.0 + +Rectangle { + property string shootImagePath: "shoot.png" + function isSuffix(str, suffix) { + return String(str).substr(String(str).length - suffix.length) == suffix + } + + id: ui + color: "#252423" + anchors.fill: parent + + Camera { + objectName: "camera" + id: camera + onError: { + console.log(errorString); + } + videoRecorder.audioBitRate: 128000 + videoRecorder.mediaContainer: "mp4" + imageCapture { + onImageSaved: { + root.exec("Camera", "onImageSaved", [path]); + ui.destroy(); + } + } + } + VideoOutput { + id: output + source: camera + width: parent.width + height: parent.height + } + + Item { + anchors.bottom: parent.bottom + width: parent.width + height: shootButton.height + BorderImage { + id: leftBackground + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: middle.left + anchors.topMargin: units.dp(2) + anchors.bottomMargin: units.dp(2) + source: "toolbar-left.png" + Image { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: parent.iconSpacing + source: "back.png" + width: units.gu(6) + height: units.gu(5) + MouseArea { + anchors.fill: parent + onClicked: { + root.exec("Camera", "cancel"); + } + } + } + } + BorderImage { + id: middle + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + height: shootButton.height + units.gu(1) + width: shootButton.width + source: "toolbar-middle.png" + Image { + id: shootButton + width: units.gu(8) + height: width + anchors.horizontalCenter: parent.horizontalCenter + source: shootImagePath + MouseArea { + anchors.fill: parent + onClicked: { + camera.imageCapture.capture(); + } + } + } + } + BorderImage { + id: rightBackground + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: middle.right + anchors.topMargin: units.dp(2) + anchors.bottomMargin: units.dp(2) + source: "toolbar-right.png" + } + } +} diff --git a/src/ubuntu/back.png b/src/ubuntu/back.png new file mode 100644 index 0000000..af78faa Binary files /dev/null and b/src/ubuntu/back.png differ diff --git a/src/ubuntu/camera.cpp b/src/ubuntu/camera.cpp new file mode 100644 index 0000000..eada5dc --- /dev/null +++ b/src/ubuntu/camera.cpp @@ -0,0 +1,143 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ + +#include "camera.h" +#include + +#include +#include +#include +#include +#include + +const char code[] = "\ +var component, object; \ +function createObject() { \ + component = Qt.createComponent(%1); \ + if (component.status == Component.Ready) \ + finishCreation(); \ + else \ + component.statusChanged.connect(finishCreation); \ +} \ +function finishCreation() { \ + CordovaWrapper.object = component.createObject(root, \ + {root: root, cordova: cordova}); \ +} \ +createObject()"; + + +Camera::Camera(Cordova *cordova): + CPlugin(cordova), + _lastScId(0), + _lastEcId(0) { +} + +bool Camera::preprocessImage(QString &path) { + bool convertToPNG = (*_options.find("encodingType")).toInt() == Camera::PNG; + int quality = (*_options.find("quality")).toInt(); + int width = (*_options.find("targetWidth")).toInt(); + int height = (*_options.find("targetHeight")).toInt(); + + QImage image(path); + if (width <= 0) + width = image.width(); + if (height <= 0) + height = image.height(); + image = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); + + QFile oldImage(path); + QTemporaryFile newImage; + + const char *type; + if (convertToPNG) { + newImage.setFileTemplate("imgXXXXXX.png"); + type = "png"; + } else { + newImage.setFileTemplate("imgXXXXXX.jpg"); + type = "jpg"; + } + + newImage.open(); + newImage.setAutoRemove(false); + image.save(newImage.fileName(), type, quality); + + path = newImage.fileName(); + oldImage.remove(); + + return true; +} + +void Camera::onImageSaved(QString path) { + bool dataURL = _options.find("destinationType")->toInt() == Camera::DATA_URL; + + QString cbParams; + if (preprocessImage(path)) { + QString absolutePath = QFileInfo(path).absoluteFilePath(); + if (dataURL) { + QFile image(absolutePath); + image.open(QIODevice::ReadOnly); + QByteArray content = image.readAll().toBase64(); + cbParams = QString("\"%1\"").arg(content.data()); + image.remove(); + } else { + cbParams = CordovaInternal::format(QUrl::fromLocalFile(absolutePath).toString()); + } + } + + this->callback(_lastScId, cbParams); + + _lastEcId = _lastScId = 0; +} + +void Camera::takePicture(int scId, int ecId, int quality, int destinationType, int/*sourceType*/, int targetWidth, int targetHeight, int encodingType, + int/*mediaType*/, bool/*allowEdit*/, bool/*correctOrientation*/, bool/*saveToPhotoAlbum*/, const QVariantMap &/*popoverOptions*/, int/*cameraDirection*/) { + if (_camera.isNull()) { + _camera = QSharedPointer(new QCamera()); + } + + if (((_lastScId || _lastEcId) && (_lastScId != scId && _lastEcId != ecId)) || !_camera->isAvailable() || _camera->lockStatus() != QCamera::Unlocked) { + this->cb(_lastEcId, "Device is busy"); + return; + } + + _options.clear(); + _options.insert("quality", quality); + _options.insert("destinationType", destinationType); + _options.insert("targetWidth", targetWidth); + _options.insert("targetHeight", targetHeight); + _options.insert("encodingType", encodingType); + + _lastScId = scId; + _lastEcId = ecId; + + QString path = m_cordova->get_app_dir() + "/../qml/CaptureWidget.qml"; + + // TODO: relative url + QString qml = QString(code).arg(CordovaInternal::format(path)); + m_cordova->execQML(qml); +} + +void Camera::cancel() { + m_cordova->execQML("CordovaWrapper.object.destroy()"); + this->cb(_lastEcId, "canceled"); + + _lastEcId = _lastScId = 0; +} diff --git a/src/ubuntu/camera.h b/src/ubuntu/camera.h new file mode 100644 index 0000000..aa06698 --- /dev/null +++ b/src/ubuntu/camera.h @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ + +#ifndef CAMERA_H +#define CAMERA_H + +#include + +#include +#include +#include +#include +#include + +class Camera: public CPlugin { + Q_OBJECT +public: + explicit Camera(Cordova *cordova); + + virtual const QString fullName() override { + return Camera::fullID(); + } + + virtual const QString shortName() override { + return "Camera"; + } + + static const QString fullID() { + return "Camera"; + } + +public slots: + void takePicture(int scId, int ecId, int quality, int destinationType, int/*sourceType*/, int targetWidth, int targetHeight, int encodingType, + int/*mediaType*/, bool/*allowEdit*/, bool/*correctOrientation*/, bool/*saveToPhotoAlbum*/, const QVariantMap &popoverOptions, int cameraDirection); + void cancel(); + + void onImageSaved(QString path); + +private: + bool preprocessImage(QString &path); + + int _lastScId; + int _lastEcId; + QSharedPointer _camera; + + QVariantMap _options; +protected: + enum DestinationType { + DATA_URL = 0, + FILE_URI = 1 + }; + enum EncodingType { + JPEG = 0, + PNG = 1 + }; +}; + +#endif // CAMERA_H diff --git a/src/ubuntu/shoot.png b/src/ubuntu/shoot.png new file mode 100644 index 0000000..c093b63 Binary files /dev/null and b/src/ubuntu/shoot.png differ diff --git a/src/ubuntu/toolbar-left.png b/src/ubuntu/toolbar-left.png new file mode 100644 index 0000000..720d7f6 Binary files /dev/null and b/src/ubuntu/toolbar-left.png differ diff --git a/src/ubuntu/toolbar-middle.png b/src/ubuntu/toolbar-middle.png new file mode 100644 index 0000000..77595bb Binary files /dev/null and b/src/ubuntu/toolbar-middle.png differ diff --git a/src/ubuntu/toolbar-right.png b/src/ubuntu/toolbar-right.png new file mode 100644 index 0000000..e4e6aa6 Binary files /dev/null and b/src/ubuntu/toolbar-right.png differ