mirror of
https://git.wownero.com/wowlet/wowlet.git
synced 2024-08-15 01:03:14 +00:00
QR code feature beta and streamer mode
This commit is contained in:
parent
5bb95053fb
commit
13331ee5e7
29 changed files with 1143 additions and 31 deletions
|
@ -382,7 +382,20 @@ if(OPENVR)
|
|||
add_definitions(-DVR_API_PUBLIC)
|
||||
add_definitions(-DOPENVR_BUILD_STATIC) # is this needed?
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/contrib/openvr")
|
||||
message(STATUS "yeepp")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/contrib/KDMacTouchBar")
|
||||
endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_library(quirc STATIC
|
||||
contrib/quirc/lib/decode.c
|
||||
contrib/quirc/lib/identify.c
|
||||
contrib/quirc/lib/quirc.c
|
||||
contrib/quirc/lib/version_db.c
|
||||
)
|
||||
target_include_directories(quirc PUBLIC contrib/quirc/lib)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
|
|
@ -89,7 +89,7 @@ RUN git clone -b libgcrypt-1.8.5 --depth 1 git://git.gnupg.org/libgcrypt.git &&
|
|||
RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \
|
||||
cd zlib && \
|
||||
git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f && \
|
||||
CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar ./configure --static --prefix=/usr/x86_64-w64-mingw32 && \
|
||||
CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar ./configure --static --prefix=/depends/x86_64-w64-mingw32 && \
|
||||
make -j$THREADS && \
|
||||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
@ -164,7 +164,7 @@ RUN git clone -b tor-0.4.5.7 --depth 1 https://git.torproject.org/tor.git && \
|
|||
--enable-static-tor \
|
||||
--with-libevent-dir=/usr/local/libevent \
|
||||
--with-openssl-dir=/usr/local/openssl \
|
||||
--with-zlib-dir=/usr/x86_64-w64-mingw32 \
|
||||
--with-zlib-dir=/depends/x86_64-w64-mingw32 \
|
||||
--disable-tool-name-check \
|
||||
--enable-fatal-warnings \
|
||||
--prefix=/usr/local/tor \
|
||||
|
@ -174,7 +174,7 @@ RUN git clone -b tor-0.4.5.7 --depth 1 https://git.torproject.org/tor.git && \
|
|||
rm -rf $(pwd) && \
|
||||
strip -s -D /usr/local/tor/bin/tor.exe
|
||||
|
||||
RUN git clone https://git.featherwallet.org/feather/monero-seed.git && \
|
||||
RUN git clone https://git.wownero.com/wowlet/monero-seed.git && \
|
||||
cd monero-seed && \
|
||||
git reset --hard 4674ef09b6faa6fe602ab5ae0b9ca8e1fd7d5e1b && \
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/depends/x86_64-w64-mingw32 \
|
||||
|
@ -183,3 +183,4 @@ RUN git clone https://git.featherwallet.org/feather/monero-seed.git && \
|
|||
make -Cbuild -j$THREADS && \
|
||||
make -Cbuild install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
|
|
7
Makefile
7
Makefile
|
@ -52,7 +52,12 @@ release-static:
|
|||
|
||||
depends:
|
||||
mkdir -p build/$(target)/release
|
||||
cd build/$(target)/release && cmake -D STATIC=ON -DREPRODUCIBLE=$(or ${SOURCE_DATE_EPOCH},OFF) -DTOR_VERSION=$(or ${TOR_VERSION}, OFF) -DOPENVR=ON -DQML=ON -DTOR_BIN=$(or ${TOR_BIN},OFF) -D DEV_MODE=$(or ${DEV_MODE},OFF) -D BUILD_TAG=$(tag) -D CMAKE_BUILD_TYPE=Debug -D CMAKE_TOOLCHAIN_FILE=$(root)/$(target)/share/toolchain.cmake ../../.. && $(MAKE)
|
||||
cd build/$(target)/release && cmake -D STATIC=ON -DREPRODUCIBLE=$(or ${SOURCE_DATE_EPOCH},OFF) -DTOR_VERSION=$(or ${TOR_VERSION}, OFF) -DTOR_BIN=$(or ${TOR_BIN},OFF) -D DEV_MODE=$(or ${DEV_MODE},OFF) -D BUILD_TAG=$(tag) -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=$(root)/$(target)/share/toolchain.cmake ../../.. && $(MAKE)
|
||||
|
||||
windows:
|
||||
mkdir -p build/$(target)/release
|
||||
cd build/$(target)/release && cmake -D STATIC=ON -DREPRODUCIBLE=$(or ${SOURCE_DATE_EPOCH},OFF) -DTOR_VERSION=$(or ${TOR_VERSION}, OFF) -DOPENVR=ON -DQML=ON -DWITH_SCANNER=ON -DTOR_BIN=$(or ${TOR_BIN},OFF) -D DEV_MODE=$(or ${DEV_MODE},OFF) -D BUILD_TAG=$(tag) -D CMAKE_BUILD_TYPE=Debug -D CMAKE_TOOLCHAIN_FILE=$(root)/$(target)/share/toolchain.cmake ../../.. && $(MAKE)
|
||||
|
||||
|
||||
windows-mxe-release: CMAKEFLAGS += -DBUILD_TAG="win-x64"
|
||||
windows-mxe-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# Set the minimum required version of CMake for this project.
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
# Set project name.
|
||||
project(OpenVRSDK)
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@ set(CMAKE_AUTOUIC ON)
|
|||
# pthread
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# PNG
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(PNG REQUIRED)
|
||||
|
||||
# Compile these source files (.h/.cpp)
|
||||
file(GLOB SOURCE_FILES
|
||||
"*.h"
|
||||
|
@ -34,9 +38,9 @@ file(GLOB SOURCE_FILES
|
|||
)
|
||||
|
||||
if(QML)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Quick Qml QuickControls2 QmlImportScanner)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Quick Qml QuickControls2 QmlImportScanner Multimedia)
|
||||
else()
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Multimedia)
|
||||
endif()
|
||||
|
||||
if(OPENVR)
|
||||
|
@ -57,6 +61,7 @@ add_subdirectory(libwalletqt)
|
|||
add_subdirectory(model)
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(openpgp)
|
||||
add_subdirectory(QR-Code-scanner)
|
||||
|
||||
qt5_add_resources(RESOURCES assets.qrc)
|
||||
|
||||
|
@ -256,7 +261,22 @@ target_link_libraries(wowlet PUBLIC
|
|||
${ICU_LIBRARIES}
|
||||
openpgp
|
||||
Threads::Threads
|
||||
${QRENCODE_LIBRARY})
|
||||
${QRENCODE_LIBRARY}
|
||||
qrdecoder
|
||||
)
|
||||
|
||||
# Link scanner
|
||||
if(WITH_SCANNER)
|
||||
target_link_libraries(wowlet PUBLIC qrscanner)
|
||||
if(LINUX AND NOT ANDROID)
|
||||
target_link_libraries(wowlet PUBLIC
|
||||
jpeg
|
||||
v4l2
|
||||
v4lconvert
|
||||
rt
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Link OpenVR
|
||||
if(OPENVR)
|
||||
|
|
22
src/QR-Code-scanner/CMakeLists.txt
Normal file
22
src/QR-Code-scanner/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
add_library(qrdecoder STATIC
|
||||
Decoder.cpp
|
||||
)
|
||||
target_link_libraries(qrdecoder
|
||||
PUBLIC
|
||||
Qt5::Gui
|
||||
PNG::PNG
|
||||
PRIVATE
|
||||
quirc
|
||||
)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_library(qrscanner
|
||||
QrCodeScanner.cpp
|
||||
QrScanThread.cpp
|
||||
)
|
||||
target_link_libraries(qrscanner
|
||||
PUBLIC
|
||||
Qt5::Multimedia
|
||||
qrdecoder
|
||||
)
|
||||
endif()
|
359
src/QR-Code-scanner/Decoder.cpp
Normal file
359
src/QR-Code-scanner/Decoder.cpp
Normal file
|
@ -0,0 +1,359 @@
|
|||
// Copyright (c) 2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include "Decoder.h"
|
||||
#include "quirc.h"
|
||||
|
||||
|
||||
QrDecoder::QrDecoder()
|
||||
: m_qr(quirc_new())
|
||||
{
|
||||
if (m_qr == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate memory");
|
||||
}
|
||||
}
|
||||
|
||||
QrDecoder::~QrDecoder()
|
||||
{
|
||||
quirc_destroy(m_qr);
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decode(const QImage &image)
|
||||
{
|
||||
if (image.format() == QImage::Format_Grayscale8)
|
||||
{
|
||||
return decodeGrayscale8(image);
|
||||
}
|
||||
return decodeGrayscale8(image.convertToFormat(QImage::Format_Grayscale8));
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decodePNG(QString pngPath) {
|
||||
struct quirc *q;
|
||||
std::vector<std::string> result;
|
||||
auto pngPathStd = pngPath.toStdString();
|
||||
auto pngPathCstr = pngPathStd.c_str();
|
||||
|
||||
q = quirc_new();
|
||||
if (!q) {
|
||||
qWarning() << "can't create quirc object";
|
||||
return result;
|
||||
}
|
||||
|
||||
int status = -1;
|
||||
if (check_if_png(pngPathCstr)) {
|
||||
status = load_png(q, pngPathCstr);
|
||||
} else {
|
||||
qWarning() << QString("Image is not a PNG: %1").arg(pngPath);
|
||||
return result;
|
||||
}
|
||||
if (status < 0) {
|
||||
quirc_destroy(q);
|
||||
return result;
|
||||
}
|
||||
|
||||
quirc_end(q);
|
||||
auto count = quirc_count(q);
|
||||
result.reserve(static_cast<size_t>(count));
|
||||
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
quirc_code code;
|
||||
quirc_extract(q, index, &code);
|
||||
|
||||
quirc_data data;
|
||||
const quirc_decode_error_t err = quirc_decode(&code, &data);
|
||||
if (err == QUIRC_SUCCESS)
|
||||
{
|
||||
result.emplace_back(&data.payload[0], &data.payload[data.payload_len]);
|
||||
}
|
||||
}
|
||||
|
||||
quirc_destroy(q);
|
||||
return result;
|
||||
}
|
||||
|
||||
// I can't seem to get this function to work, we'll use dgbutil.h instead
|
||||
std::vector<std::string> QrDecoder::decodeGrayscale8(const QImage &image)
|
||||
{
|
||||
if (quirc_resize(m_qr, image.width(), image.height()) < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate video memory");
|
||||
}
|
||||
|
||||
uint8_t *rawImage = quirc_begin(m_qr, nullptr, nullptr);
|
||||
if (rawImage == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get image buffer");
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
std::copy(image.constBits(), image.constBits() + image.sizeInBytes(), rawImage);
|
||||
#else
|
||||
std::copy(image.constBits(), image.constBits() + image.byteCount(), rawImage);
|
||||
#endif
|
||||
quirc_end(m_qr);
|
||||
|
||||
const int count = quirc_count(m_qr);
|
||||
if (count < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get the number of recognized QR-codes");
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
result.reserve(static_cast<size_t>(count));
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
quirc_code code;
|
||||
quirc_extract(m_qr, index, &code);
|
||||
|
||||
quirc_data data;
|
||||
const quirc_decode_error_t err = quirc_decode(&code, &data);
|
||||
if (err == QUIRC_SUCCESS)
|
||||
{
|
||||
result.emplace_back(&data.payload[0], &data.payload[data.payload_len]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* quirc -- QR-code recognition library
|
||||
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
static const char *data_type_str(int dt)
|
||||
{
|
||||
switch (dt) {
|
||||
case QUIRC_DATA_TYPE_NUMERIC: return "NUMERIC";
|
||||
case QUIRC_DATA_TYPE_ALPHA: return "ALPHA";
|
||||
case QUIRC_DATA_TYPE_BYTE: return "BYTE";
|
||||
case QUIRC_DATA_TYPE_KANJI: return "KANJI";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void QrDecoder::dump_data(const struct quirc_data *data)
|
||||
{
|
||||
printf(" Version: %d\n", data->version);
|
||||
printf(" ECC level: %c\n", "MLHQ"[data->ecc_level]);
|
||||
printf(" Mask: %d\n", data->mask);
|
||||
printf(" Data type: %d (%s)\n",
|
||||
data->data_type, data_type_str(data->data_type));
|
||||
printf(" Length: %d\n", data->payload_len);
|
||||
printf(" Payload: %s\n", data->payload);
|
||||
|
||||
if (data->eci)
|
||||
printf(" ECI: %d\n", data->eci);
|
||||
}
|
||||
|
||||
void QrDecoder::dump_cells(const struct quirc_code *code)
|
||||
{
|
||||
int u, v;
|
||||
|
||||
printf(" %d cells, corners:", code->size);
|
||||
for (u = 0; u < 4; u++)
|
||||
printf(" (%d,%d)", code->corners[u].x,
|
||||
code->corners[u].y);
|
||||
printf("\n");
|
||||
|
||||
for (v = 0; v < code->size; v++) {
|
||||
printf(" ");
|
||||
for (u = 0; u < code->size; u++) {
|
||||
int p = v * code->size + u;
|
||||
|
||||
if (code->cell_bitmap[p >> 3] & (1 << (p & 7)))
|
||||
printf("[]");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* hacked from https://dev.w3.org/Amaya/libpng/example.c
|
||||
*
|
||||
* Check if a file is a PNG image using png_sig_cmp(). Returns 1 if the given
|
||||
* file is a PNG and 0 otherwise.
|
||||
*/
|
||||
#define PNG_BYTES_TO_CHECK 4
|
||||
int QrDecoder::check_if_png(const char *filename)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *infile = NULL;
|
||||
unsigned char buf[PNG_BYTES_TO_CHECK];
|
||||
|
||||
/* Open the prospective PNG file. */
|
||||
if ((infile = fopen(filename, "rb")) == NULL)
|
||||
goto out;
|
||||
|
||||
/* Read in some of the signature bytes */
|
||||
if (fread(buf, 1, PNG_BYTES_TO_CHECK, infile) != PNG_BYTES_TO_CHECK)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
|
||||
* png_sig_cmp() returns zero if the image is a PNG and nonzero if it
|
||||
* isn't a PNG.
|
||||
*/
|
||||
if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0)
|
||||
ret = 1;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
out:
|
||||
if (infile)
|
||||
fclose(infile);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int QrDecoder::load_png(struct quirc *q, const char *filename)
|
||||
{
|
||||
int width, height, rowbytes, interlace_type, number_passes = 1;
|
||||
png_uint_32 trns;
|
||||
png_byte color_type, bit_depth;
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
FILE *infile = NULL;
|
||||
uint8_t *image;
|
||||
int ret = -1;
|
||||
int pass;
|
||||
|
||||
if ((infile = fopen(filename, "rb")) == NULL)
|
||||
goto out;
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png_ptr)
|
||||
goto out;
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
goto out;
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
goto out;
|
||||
|
||||
png_init_io(png_ptr, infile);
|
||||
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
|
||||
|
||||
// Read any color_type into 8bit depth, Grayscale format.
|
||||
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
||||
|
||||
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
||||
|
||||
if ((trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
|
||||
if (bit_depth == 16)
|
||||
#if PNG_LIBPNG_VER >= 10504
|
||||
png_set_scale_16(png_ptr);
|
||||
#else
|
||||
png_set_strip_16(png_ptr);
|
||||
#endif
|
||||
|
||||
if ((trns) || color_type & PNG_COLOR_MASK_ALPHA)
|
||||
png_set_strip_alpha(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE ||
|
||||
color_type == PNG_COLOR_TYPE_RGB ||
|
||||
color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
|
||||
png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1);
|
||||
}
|
||||
|
||||
if (interlace_type != PNG_INTERLACE_NONE)
|
||||
number_passes = png_set_interlace_handling(png_ptr);
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
width = png_get_image_width(png_ptr, info_ptr);
|
||||
height = png_get_image_height(png_ptr, info_ptr);
|
||||
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
if (rowbytes != width) {
|
||||
fprintf(stderr,
|
||||
"load_png: expected rowbytes to be %u but got %u\n",
|
||||
width, rowbytes);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (quirc_resize(q, width, height) < 0)
|
||||
goto out;
|
||||
|
||||
image = quirc_begin(q, NULL, NULL);
|
||||
|
||||
for (pass = 0; pass < number_passes; pass++) {
|
||||
int y;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
png_bytep row_pointer = image + y * width;
|
||||
png_read_rows(png_ptr, &row_pointer, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
|
||||
ret = 0;
|
||||
/* FALLTHROUGH */
|
||||
out:
|
||||
/* cleanup */
|
||||
if (png_ptr) {
|
||||
if (info_ptr)
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
else
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||
}
|
||||
if (infile)
|
||||
fclose(infile);
|
||||
return (ret);
|
||||
}
|
72
src/QR-Code-scanner/Decoder.h
Normal file
72
src/QR-Code-scanner/Decoder.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <QImage>
|
||||
|
||||
#include <png.h>
|
||||
|
||||
struct quirc;
|
||||
|
||||
class QrDecoder
|
||||
{
|
||||
public:
|
||||
QrDecoder(const QrDecoder &) = delete;
|
||||
QrDecoder &operator=(const QrDecoder &) = delete;
|
||||
|
||||
QrDecoder();
|
||||
~QrDecoder();
|
||||
|
||||
std::vector<std::string> decode(const QImage &image);
|
||||
std::vector<std::string> decodePNG(QString pngPath);
|
||||
|
||||
private:
|
||||
/* Dump decoded information on stdout. */
|
||||
void dump_data(const struct quirc_data *data);
|
||||
|
||||
/* Dump a grid cell map on stdout. */
|
||||
void dump_cells(const struct quirc_code *code);
|
||||
|
||||
/* Check if a file is a PNG image.
|
||||
*
|
||||
* returns 1 if the given file is a PNG and 0 otherwise.
|
||||
*/
|
||||
int check_if_png(const char *filename);
|
||||
|
||||
/* Read a PNG image into the decoder.
|
||||
*
|
||||
* Note that you must call quirc_end() if the function returns
|
||||
* successfully (0).
|
||||
*/
|
||||
int load_png(struct quirc *q, const char *filename);
|
||||
|
||||
private:
|
||||
std::vector<std::string> decodeGrayscale8(const QImage &image);
|
||||
|
||||
private:
|
||||
quirc *m_qr;
|
||||
};
|
92
src/QR-Code-scanner/QrCodeScanner.cpp
Normal file
92
src/QR-Code-scanner/QrCodeScanner.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QrCodeScanner.h"
|
||||
#include <QVideoProbe>
|
||||
#include <QCamera>
|
||||
|
||||
QrCodeScanner::QrCodeScanner(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_processTimerId(-1)
|
||||
, m_processInterval(750)
|
||||
, m_enabled(true)
|
||||
{
|
||||
m_probe = new QVideoProbe(this);
|
||||
m_thread = new QrScanThread(this);
|
||||
m_thread->start();
|
||||
QObject::connect(m_thread, SIGNAL(decoded(QString)), this, SIGNAL(decoded(QString)));
|
||||
QObject::connect(m_thread, SIGNAL(notifyError(const QString &, bool)), this, SIGNAL(notifyError(const QString &, bool)));
|
||||
connect(m_probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
|
||||
}
|
||||
void QrCodeScanner::setSource(QCamera *camera)
|
||||
{
|
||||
m_probe->setSource(camera);
|
||||
}
|
||||
void QrCodeScanner::processFrame(QVideoFrame frame)
|
||||
{
|
||||
if(frame.isValid()){
|
||||
m_curFrame = frame;
|
||||
}
|
||||
}
|
||||
bool QrCodeScanner::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
void QrCodeScanner::setEnabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
if(!enabled && (m_processTimerId != -1) )
|
||||
{
|
||||
this->killTimer(m_processTimerId);
|
||||
m_processTimerId = -1;
|
||||
}
|
||||
else if (enabled && (m_processTimerId == -1) )
|
||||
{
|
||||
m_processTimerId = this->startTimer(m_processInterval);
|
||||
}
|
||||
emit enabledChanged();
|
||||
}
|
||||
void QrCodeScanner::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if( (event->timerId() == m_processTimerId) ){
|
||||
m_thread->addFrame(m_curFrame);
|
||||
}
|
||||
}
|
||||
|
||||
QrCodeScanner::~QrCodeScanner()
|
||||
{
|
||||
m_thread->stop();
|
||||
m_thread->quit();
|
||||
if(!m_thread->wait(5000))
|
||||
{
|
||||
m_thread->terminate();
|
||||
m_thread->wait();
|
||||
}
|
||||
|
||||
}
|
||||
|
73
src/QR-Code-scanner/QrCodeScanner.h
Normal file
73
src/QR-Code-scanner/QrCodeScanner.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QRCODESCANNER_H_
|
||||
#define QRCODESCANNER_H_
|
||||
|
||||
#include <QImage>
|
||||
#include <QVideoFrame>
|
||||
#include "QrScanThread.h"
|
||||
|
||||
class QVideoProbe;
|
||||
class QCamera;
|
||||
|
||||
class QrCodeScanner : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
||||
|
||||
public:
|
||||
QrCodeScanner(QObject *parent = Q_NULLPTR);
|
||||
~QrCodeScanner();
|
||||
void setSource(QCamera*);
|
||||
|
||||
bool enabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
public Q_SLOTS:
|
||||
void processFrame(QVideoFrame);
|
||||
|
||||
Q_SIGNALS:
|
||||
void enabledChanged();
|
||||
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *);
|
||||
QrScanThread *m_thread;
|
||||
int m_processTimerId;
|
||||
int m_processInterval;
|
||||
int m_enabled;
|
||||
QVideoFrame m_curFrame;
|
||||
QVideoProbe *m_probe;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
90
src/QR-Code-scanner/QrScanThread.cpp
Normal file
90
src/QR-Code-scanner/QrScanThread.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QrScanThread.h"
|
||||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
extern QImage qt_imageFromVideoFrame(const QVideoFrame &f);
|
||||
#endif
|
||||
|
||||
QrScanThread::QrScanThread(QObject *parent)
|
||||
: QThread(parent)
|
||||
,m_running(true)
|
||||
{
|
||||
}
|
||||
|
||||
void QrScanThread::processQImage(const QImage &qimg)
|
||||
{
|
||||
try {
|
||||
for (const std::string &code : m_decoder.decode(qimg))
|
||||
{
|
||||
emit decoded(QString::fromStdString(code));
|
||||
}
|
||||
}
|
||||
catch(std::exception &e) {
|
||||
qDebug() << "ERROR: " << e.what();
|
||||
emit notifyError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void QrScanThread::processVideoFrame(const QVideoFrame &frame)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
processQImage( qt_imageFromVideoFrame(frame) );
|
||||
#else
|
||||
processQImage(frame.image());
|
||||
#endif
|
||||
}
|
||||
|
||||
void QrScanThread::stop()
|
||||
{
|
||||
m_running = false;
|
||||
m_waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
void QrScanThread::addFrame(const QVideoFrame &frame)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_queue.append(frame);
|
||||
m_waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
void QrScanThread::run()
|
||||
{
|
||||
QVideoFrame frame;
|
||||
while(m_running) {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
while(m_queue.isEmpty() && m_running)
|
||||
m_waitCondition.wait(&m_mutex);
|
||||
if(!m_queue.isEmpty())
|
||||
processVideoFrame(m_queue.takeFirst());
|
||||
}
|
||||
}
|
||||
|
66
src/QR-Code-scanner/QrScanThread.h
Normal file
66
src/QR-Code-scanner/QrScanThread.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _QRSCANTHREAD_H_
|
||||
#define _QRSCANTHREAD_H_
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QEvent>
|
||||
#include <QVideoFrame>
|
||||
#include <QCamera>
|
||||
|
||||
#include "Decoder.h"
|
||||
|
||||
class QrScanThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QrScanThread(QObject *parent = Q_NULLPTR);
|
||||
void addFrame(const QVideoFrame &frame);
|
||||
virtual void stop();
|
||||
|
||||
Q_SIGNALS:
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
void processVideoFrame(const QVideoFrame &);
|
||||
void processQImage(const QImage &);
|
||||
|
||||
private:
|
||||
QrDecoder m_decoder;
|
||||
bool m_running;
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
QList<QVideoFrame> m_queue;
|
||||
};
|
||||
#endif
|
|
@ -89,8 +89,9 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
|||
if(!this->configDirectory.endsWith('/'))
|
||||
this->configDirectory = QString("%1/").arg(this->configDirectory);
|
||||
#endif
|
||||
this->configDirectoryVR = QString("%1%2").arg(this->configDirectory, "vr");
|
||||
|
||||
// Config
|
||||
// Create some directories
|
||||
createConfigDirectory(this->configDirectory);
|
||||
|
||||
// if(this->cmdargs->isSet("stagenet"))
|
||||
|
@ -545,8 +546,8 @@ void AppContext::onWSCCS(const QJsonArray &ccs_data) {
|
|||
}
|
||||
|
||||
void AppContext::createConfigDirectory(const QString &dir) {
|
||||
QString config_dir_tor = QString("%1%2").arg(dir).arg("tor");
|
||||
QString config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
|
||||
auto config_dir_tor = QString("%1%2").arg(dir).arg("tor");
|
||||
auto config_dir_tordata = QString("%1%2").arg(dir).arg("tor/data");
|
||||
|
||||
QStringList createDirs({dir, config_dir_tor, config_dir_tordata});
|
||||
for(const auto &d: createDirs) {
|
||||
|
@ -556,6 +557,13 @@ void AppContext::createConfigDirectory(const QString &dir) {
|
|||
throw std::runtime_error("Could not create directory " + d.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
auto config_dir_vr = QString("%1%2").arg(dir, "vr");
|
||||
if(!Utils::dirExists(config_dir_vr)) {
|
||||
qDebug() << QString("Creating directory: %1").arg(config_dir_vr);
|
||||
if (!QDir().mkpath(config_dir_vr))
|
||||
throw std::runtime_error("Could not create directory " + config_dir_vr.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
void AppContext::createWalletWithoutSpecifyingSeed(const QString &name, const QString &password) {
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
QString accountName;
|
||||
QString configRoot;
|
||||
QString configDirectory;
|
||||
QString configDirectoryVR;
|
||||
QString defaultWalletDir;
|
||||
QString defaultWalletDirRoot;
|
||||
QString tmpTxDescription;
|
||||
|
|
|
@ -26,6 +26,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
|||
{Config::donateBeg,{QS("donateBeg"), 1}},
|
||||
{Config::skin,{QS("skin"), "light"}},
|
||||
{Config::openVRSkin,{QS("openVRSkin"), "default"}},
|
||||
{Config::openVRStreamerMode,{QS("openVRStreamerMode"), false}},
|
||||
{Config::preferredFiatCurrency,{QS("preferredFiatCurrency"), "USD"}},
|
||||
{Config::blockExplorer,{QS("blockExplorer"), "explore.wownero.com"}},
|
||||
{Config::walletDirectory,{QS("walletDirectory"), ""}},
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
autoOpenWalletPath,
|
||||
skin,
|
||||
openVRSkin,
|
||||
openVRStreamerMode,
|
||||
preferredFiatCurrency,
|
||||
blockExplorer,
|
||||
walletDirectory,
|
||||
|
|
|
@ -42,6 +42,12 @@ QByteArray Utils::fileOpen(const QString &path) {
|
|||
return data;
|
||||
}
|
||||
|
||||
qint64 Utils::fileModifiedAge(const QString &path) {
|
||||
QFileInfo fileInfo;
|
||||
fileInfo.setFile(path);
|
||||
return (QDateTime::currentSecsSinceEpoch() - fileInfo.lastModified().toSecsSinceEpoch());
|
||||
}
|
||||
|
||||
QByteArray Utils::fileOpenQRC(const QString &path) {
|
||||
QFile file(path);
|
||||
if(!file.open(QIODevice::ReadOnly)) {
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
static bool fileExists(const QString &path);
|
||||
static QByteArray fileOpen(const QString &path);
|
||||
static QByteArray fileOpenQRC(const QString &path);
|
||||
static qint64 fileModifiedAge(const QString &path);
|
||||
static void desktopNotify(const QString &title, const QString &message, int duration);
|
||||
static bool fileWrite(const QString &path, const QString &data);
|
||||
static QStringList fileFind(const QRegExp &pattern, const QString &baseDir, int level, int depth, int maxPerDir);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QQmlComponent>
|
||||
#include <QObject>
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QQmlApplicationEngine>
|
||||
|
@ -42,9 +43,15 @@ namespace wowletvr {
|
|||
// turn on auto tx commits
|
||||
ctx->autoCommitTx = true;
|
||||
|
||||
// write icon to disk so openvr overlay can refer to it
|
||||
// QR code scanning from screenshots
|
||||
m_qrScreenshotPreviewPath = ctx->configDirectoryVR + "/screenshot_preview";
|
||||
m_qrScreenshotImagePath = ctx->configDirectoryVR + "/screenshot";
|
||||
m_qrScreenshotTimer.setSingleShot(true);
|
||||
connect(&m_qrScreenshotTimer, &QTimer::timeout, this, &WowletVR::onCheckQRScreenshot);
|
||||
|
||||
// write icon to disk so openvr overlay can use it
|
||||
auto icon = ":/assets/images/wowlet.png";
|
||||
if (Utils::fileExists(icon)) {
|
||||
if(Utils::fileExists(icon)) {
|
||||
QFile f(icon);
|
||||
QFileInfo fileInfo(f);
|
||||
auto icon_path = QDir(ctx->configDirectory).filePath(fileInfo.fileName());
|
||||
|
@ -140,10 +147,79 @@ namespace wowletvr {
|
|||
|
||||
themes[themeName] = map;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void WowletVR::takeQRScreenshot() {
|
||||
if(m_qrScreenshotTimer.isActive())
|
||||
return;
|
||||
|
||||
m_controller->takeQRScreenshot(m_qrScreenshotPreviewPath, m_qrScreenshotImagePath);
|
||||
m_qrScreenshotTimer.start(1000);
|
||||
}
|
||||
|
||||
void WowletVR::onCheckQRScreenshot() {
|
||||
qDebug() << "onCheckQRScreenshot()";
|
||||
QString msg;
|
||||
auto path = m_qrScreenshotPreviewPath + ".png";
|
||||
auto pathPreview = m_qrScreenshotPreviewPath + "_inverted.png";
|
||||
|
||||
qDebug() << "path: " + path << " inverted: " + pathPreview;
|
||||
|
||||
if(!Utils::fileExists(path)) {
|
||||
msg = "Screenshot was not saved to disk.";
|
||||
qWarning() << msg;
|
||||
emit qrScreenshotFailed(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
auto age = Utils::fileModifiedAge(path);
|
||||
if (age >= 5) {
|
||||
msg = "Screenshot on disk too old. Leftover from the last time?";
|
||||
qWarning() << msg;
|
||||
emit qrScreenshotFailed(msg);
|
||||
QFile file (path);
|
||||
file.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
auto results = m_qrDecoder.decodePNG(path);
|
||||
auto result = wowletvr::WowletVR::checkQRScreenshotResults(results);
|
||||
qDebug() << "no initial results";
|
||||
if(result.isEmpty()) {
|
||||
qDebug() << "trying to invert the image";
|
||||
// lets try to invert the image
|
||||
QImage image(path);
|
||||
image.invertPixels();
|
||||
image.save(pathPreview);
|
||||
results = m_qrDecoder.decodePNG(pathPreview);
|
||||
result = wowletvr::WowletVR::checkQRScreenshotResults(results);
|
||||
if(!result.isEmpty()) {
|
||||
qDebug() << "Found QR code after inverting the image.";
|
||||
emit qrScreenshotSuccess(result);
|
||||
QFile file (path);
|
||||
file.remove();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "QR code found.";
|
||||
emit qrScreenshotSuccess(result);
|
||||
QFile file (path);
|
||||
file.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
emit qrScreenshotSuccess("No QR code could be detected.");
|
||||
}
|
||||
|
||||
QString WowletVR::checkQRScreenshotResults(std::vector<std::string> results) {
|
||||
auto results_count = results.size();
|
||||
if(results_count == 1)
|
||||
return QString::fromStdString(results[0]);
|
||||
return "";
|
||||
}
|
||||
|
||||
WowletVR::~WowletVR() {
|
||||
// bla
|
||||
int wegeg = 1;
|
||||
}
|
||||
}
|
|
@ -10,11 +10,13 @@
|
|||
#include <QtQml>
|
||||
#include <QGuiApplication>
|
||||
#include <QClipboard>
|
||||
#include <QTimer>
|
||||
#include <globals.h>
|
||||
|
||||
#include "overlaycontroller.h"
|
||||
#include "appcontext.h"
|
||||
#include "utils/config.h"
|
||||
#include "QR-Code-scanner/Decoder.h"
|
||||
|
||||
namespace wowletvr {
|
||||
|
||||
|
@ -57,6 +59,14 @@ namespace wowletvr {
|
|||
m_pClipboard->setText(text, QClipboard::Selection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void setStreamerMode(bool status) {
|
||||
config()->set(Config::openVRStreamerMode, status);
|
||||
}
|
||||
|
||||
Q_INVOKABLE bool getStreamerMode() {
|
||||
return config()->get(Config::openVRStreamerMode).toBool();
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString preferredFiat() {
|
||||
return config()->get(Config::preferredFiatCurrency).toString();
|
||||
}
|
||||
|
@ -78,14 +88,31 @@ namespace wowletvr {
|
|||
return QString("~%1").arg(QString::number(conversionAmount, 'f', 2));
|
||||
}
|
||||
|
||||
Q_INVOKABLE void takeQRScreenshot();
|
||||
|
||||
signals:
|
||||
void qrScreenshotFailed(QString error);
|
||||
void qrScreenshotSuccess(QString address);
|
||||
|
||||
private slots:
|
||||
void onCheckQRScreenshot();
|
||||
|
||||
private:
|
||||
AppContext *ctx;
|
||||
QCommandLineParser *m_parser;
|
||||
QQmlEngine m_engine;
|
||||
QQmlComponent *m_component;
|
||||
bool desktopMode = false;
|
||||
wowletvr::OverlayController *m_controller;
|
||||
|
||||
bool desktopMode = false;
|
||||
QString m_qrScreenshotPreviewPath;
|
||||
QString m_qrScreenshotImagePath;
|
||||
|
||||
QCommandLineParser *m_parser;
|
||||
QClipboard *m_pClipboard;
|
||||
QTimer m_qrScreenshotTimer;
|
||||
QrDecoder m_qrDecoder;
|
||||
|
||||
static QString checkQRScreenshotResults(std::vector<std::string> results);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ Rectangle {
|
|||
property var themes: {}
|
||||
property string theme: "default"
|
||||
property string fiatSymbol: "USD"
|
||||
property bool streamerMode: false
|
||||
signal initTheme();
|
||||
|
||||
// Components that have been dynamically created need to redraw
|
||||
|
@ -307,6 +308,7 @@ Rectangle {
|
|||
// Start animating the background
|
||||
gradientBackgroundTimer.start();
|
||||
|
||||
// init some theme stuff
|
||||
try {
|
||||
appWindow.themes = WowletVR.getThemes();
|
||||
appWindow.theme = WowletVR.getCurrentTheme();
|
||||
|
@ -329,9 +331,13 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
appWindow.changeTheme(appWindow.theme);
|
||||
appWindow.initTheme();
|
||||
|
||||
// streamer mode enabled?
|
||||
try {
|
||||
appWindow.streamerMode = WowletVR.getStreamerMode();
|
||||
} catch(err){}
|
||||
}
|
||||
|
||||
function changeTheme(theme) {
|
||||
|
|
85
src/vr/main2.qml
Normal file
85
src/vr/main2.qml
Normal file
|
@ -0,0 +1,85 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Dialogs 1.2
|
||||
|
||||
import "."
|
||||
import "mock/Windows.js" as Windows
|
||||
import "mock/Version.js" as Version
|
||||
import "mock/NetworkType.js" as NetworkType
|
||||
import "mock/Settings.js" as Settings
|
||||
import "mock"
|
||||
import "qml/common"
|
||||
|
||||
import "qml/."
|
||||
|
||||
|
||||
Rectangle {
|
||||
width: 1600
|
||||
height: 800
|
||||
color: "red"
|
||||
|
||||
property var currentWallet;
|
||||
property bool disconnected: currentWallet ? currentWallet.disconnected : false
|
||||
|
||||
property WalletDashboard WalletDashboard: WalletDashboard {
|
||||
stackView: walletView
|
||||
}
|
||||
|
||||
property SendPage sendPage: SendPage {
|
||||
stackView: walletView
|
||||
visible: false
|
||||
}
|
||||
|
||||
property ReceivePage receivePage: ReceivePage {
|
||||
stackView: walletView
|
||||
visible: false
|
||||
}
|
||||
|
||||
StackView {
|
||||
id: walletView
|
||||
anchors.fill: parent
|
||||
|
||||
pushEnter: Transition {
|
||||
PropertyAnimation {
|
||||
property: "x"
|
||||
from: walletView.width
|
||||
to: 0
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
pushExit: Transition {
|
||||
PropertyAnimation {
|
||||
property: "x"
|
||||
from: 0
|
||||
to: -walletView.width
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
popEnter: Transition {
|
||||
PropertyAnimation {
|
||||
property: "x"
|
||||
from: -walletView.width
|
||||
to: 0
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
popExit: Transition {
|
||||
PropertyAnimation {
|
||||
property: "x"
|
||||
from: 0
|
||||
to: walletView.width
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
initialItem: WalletDashboard
|
||||
}
|
||||
}
|
|
@ -459,4 +459,16 @@ const vr::VROverlayHandle_t& OverlayController::overlayThumbnailHandle() {
|
|||
return m_ulOverlayThumbnailHandle;
|
||||
}
|
||||
|
||||
void OverlayController::takeQRScreenshot(const QString &previewPath, const QString &imagePath) {
|
||||
vr::IVRScreenshots *screen_taker = vr::VRScreenshots();
|
||||
|
||||
vr::ScreenshotHandle_t taker_handle;
|
||||
screen_taker->RequestScreenshot(&taker_handle,
|
||||
vr::EVRScreenshotType::VRScreenshotType_Mono,
|
||||
previewPath.toStdString().c_str(),
|
||||
imagePath.toStdString().c_str()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
} // namespace wowletvr
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
#include "openvr_init.h"
|
||||
#include "vr/utils/paths.h"
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace application_strings
|
||||
{
|
||||
|
@ -59,6 +58,7 @@ public:
|
|||
void Shutdown();
|
||||
|
||||
Q_INVOKABLE void exitApp();
|
||||
void takeQRScreenshot(const QString &previewPath, const QString &imagePath);
|
||||
|
||||
bool isDashboardVisible()
|
||||
{
|
||||
|
@ -117,8 +117,6 @@ private:
|
|||
bool m_keyPressOneState = false;
|
||||
bool m_keyPressTwoState = false;
|
||||
|
||||
AppContext *m_ctx;
|
||||
|
||||
public slots:
|
||||
void renderOverlay();
|
||||
void OnRenderRequest();
|
||||
|
|
BIN
src/vr/qml.rcc
Normal file
BIN
src/vr/qml.rcc
Normal file
Binary file not shown.
|
@ -48,7 +48,7 @@ ColumnLayout {
|
|||
Layout.rightMargin: 40
|
||||
Layout.fillWidth: true
|
||||
fontSize: 21
|
||||
text: "Shoutouts: matzman666, qvqc, ez, Gatto, RAGEHAÜZ, cisme, wowario, lza_menace, jwinterm, nioc, asymptotically, azy, selsta, kico, laura, thrmo, rottensox, solar, bl4sty, scoobybejesus"
|
||||
text: "Shoutouts: matzman666, qvqc, ez, Gatto, RAGEHAÜZ, cisme, wowario, lza_menace, jwinterm, nioc, asymptotically, azy, selsta, kico, laura, thrmo, rottensox, GNVR, solar, bl4sty, scoobybejesus, Valve Corporation for OpenVR"
|
||||
wrap: true
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,13 @@ ColumnLayout {
|
|||
wrap: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: Style.dividerColor
|
||||
height: 1
|
||||
Layout.topMargin: 10
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 30
|
||||
|
||||
|
@ -67,6 +74,43 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 30
|
||||
|
||||
MyText {
|
||||
text: "Streamer mode (" + (appWindow.streamerMode ? "ON" : "OFF") + ")"
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 56
|
||||
|
||||
MyPushButton {
|
||||
Layout.preferredWidth: 100
|
||||
enabled: !appWindow.streamerMode
|
||||
opacity: !appWindow.streamerMode ? 1.0 : 0.3
|
||||
text: "On"
|
||||
onClicked: {
|
||||
appWindow.streamerMode = !appWindow.streamerMode;
|
||||
WowletVR.setStreamerMode(appWindow.streamerMode);
|
||||
}
|
||||
}
|
||||
|
||||
MyPushButton {
|
||||
Layout.preferredWidth: 100
|
||||
enabled: appWindow.streamerMode
|
||||
opacity: appWindow.streamerMode ? 1.0 : 0.3
|
||||
text: "Off"
|
||||
|
||||
onClicked: {
|
||||
appWindow.streamerMode = !appWindow.streamerMode;
|
||||
WowletVR.setStreamerMode(appWindow.streamerMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
|
@ -108,7 +108,12 @@ Rectangle {
|
|||
anchors.bottom: parent.bottom
|
||||
fontSize: 30
|
||||
fontBold: true
|
||||
text: appWindow.balanceFormatted
|
||||
text: {
|
||||
if(!appWindow.streamerMode)
|
||||
return appWindow.balanceFormatted;
|
||||
else
|
||||
return "HIDDEN";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +241,10 @@ Rectangle {
|
|||
text: {
|
||||
let rtn = "Balance: ";
|
||||
try {
|
||||
if(!appWindow.streamerMode)
|
||||
rtn += WowletVR.wowToFiat(appWindow.spendable);
|
||||
else
|
||||
rtn += "HIDDEN";
|
||||
} catch(err) {
|
||||
rtn += "ERROR";
|
||||
}
|
||||
|
|
|
@ -9,22 +9,25 @@ ColumnLayout {
|
|||
id: root
|
||||
spacing: 20
|
||||
|
||||
property bool takingScreenshot: false
|
||||
Layout.fillWidth: true
|
||||
|
||||
MyText {
|
||||
Layout.fillWidth: true
|
||||
wrap: true
|
||||
fontColor: Style.fontColorBright
|
||||
text: "Look at a QR code in VR and take a screenshot."
|
||||
text: "Look at a QR code and press the button below to take a screenshot. Note: make sure to look at the center of the QR code. The parser works best with simple, straight-forward QR codes. When using more complex QR codes, make sure to properly fill your screen with the QR code itself (plus some margins)."
|
||||
}
|
||||
|
||||
MyPushButton {
|
||||
id: continueButton
|
||||
text: "Take in-game screenshot"
|
||||
Layout.preferredWidth: 490
|
||||
opacity: takingScreenshot ? 0.0 : 1.0
|
||||
|
||||
onClicked: {
|
||||
// QR thingy
|
||||
root.takingScreenshot = true;
|
||||
WowletVR.takeQRScreenshot();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,8 +45,33 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
function reset() {
|
||||
Connections {
|
||||
target: WowletVR
|
||||
|
||||
function onQrScreenshotSuccess(address) {
|
||||
root.takingScreenshot = false;
|
||||
console.log("onPinLookupReceived", address);
|
||||
if(!address.startsWith("wownero:")) {
|
||||
messagePopup.showMessage("Invalid QR code", "QR data did not start with \"wownero:\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if(sendStateView.currentView === sendStateView.qrPage) {
|
||||
sendStateController.destinationAddress = address.slice(8);
|
||||
sendStateView.state = "transferPage";
|
||||
}
|
||||
}
|
||||
|
||||
function onQrScreenshotFailed(msg) {
|
||||
root.takingScreenshot = false;
|
||||
console.log("onQrScreenshotFailed", msg);
|
||||
messagePopup.showMessage("QR scan failure", msg)
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
root.takingScreenshot = false;
|
||||
}
|
||||
|
||||
function onPageCompleted(previousView){
|
||||
|
|
Loading…
Reference in a new issue