Browse Source

Merge pull request #629 from sje397/master

QR Code generation via libqrencode
0.8
Wladimir J. van der Laan 13 years ago
parent
commit
96b1e085c3
  1. 14
      bitcoin-qt.pro
  2. 1
      contrib/gitian-descriptors/gitian.yml
  3. 3
      doc/build-osx.txt
  4. 8
      doc/build-unix.txt
  5. 4
      src/makefile.osx
  6. 30
      src/qt/addressbookpage.cpp
  7. 1
      src/qt/addressbookpage.h
  8. 1
      src/qt/bitcoin.qrc
  9. 11
      src/qt/forms/addressbookpage.ui
  10. 213
      src/qt/forms/qrcodedialog.ui
  11. 106
      src/qt/qrcodedialog.cpp
  12. 37
      src/qt/qrcodedialog.h
  13. BIN
      src/qt/res/images/qrcode.png

14
bitcoin-qt.pro

@ -19,6 +19,14 @@ OBJECTS_DIR = build
MOC_DIR = build MOC_DIR = build
UI_DIR = build UI_DIR = build
# use: qmake "USE_QRCODE=1"
# libqrencode (http://fukuchi.org/works/qrencode/index.en.html) must be installed for support
contains(USE_QRCODE, 1) {
message(Building with QRCode support)
DEFINES += USE_QRCODE
LIBS += -lqrencode
}
# use: qmake "RELEASE=1" # use: qmake "RELEASE=1"
contains(RELEASE, 1) { contains(RELEASE, 1) {
# Mac: compile for maximum compatibility (10.5, 32-bit) # Mac: compile for maximum compatibility (10.5, 32-bit)
@ -199,6 +207,12 @@ FORMS += \
src/qt/forms/sendcoinsentry.ui \ src/qt/forms/sendcoinsentry.ui \
src/qt/forms/askpassphrasedialog.ui src/qt/forms/askpassphrasedialog.ui
contains(USE_QRCODE, 1) {
HEADERS += src/qt/qrcodedialog.h
SOURCES += src/qt/qrcodedialog.cpp
FORMS += src/qt/forms/qrcodedialog.ui
}
CODECFORTR = UTF-8 CODECFORTR = UTF-8
# for lrelease/lupdate # for lrelease/lupdate

1
contrib/gitian-descriptors/gitian.yml

@ -16,6 +16,7 @@ packages:
- "libssl-dev" - "libssl-dev"
- "git-core" - "git-core"
- "unzip" - "unzip"
- "qrencode"
reference_datetime: "2011-01-30 00:00:00" reference_datetime: "2011-01-30 00:00:00"
remotes: remotes:
- "url": "https://github.com/bitcoin/bitcoin.git" - "url": "https://github.com/bitcoin/bitcoin.git"

3
doc/build-osx.txt

@ -43,6 +43,9 @@ pushd bitcoin/contrib/minipupnpc; sudo port install; popd
(this will be unnecessary soon, you will just port install miniupnpc (this will be unnecessary soon, you will just port install miniupnpc
along with the rest of the dependencies). along with the rest of the dependencies).
Optionally install qrencode (and set USE_QRCODE=1):
sudo port install qrencode
4. Now you should be able to build bitcoind: 4. Now you should be able to build bitcoind:
cd bitcoin/src cd bitcoin/src

8
doc/build-unix.txt

@ -29,6 +29,7 @@ Dependencies
libdb4.8 Berkeley DB Blockchain & wallet storage libdb4.8 Berkeley DB Blockchain & wallet storage
libboost Boost C++ Library libboost Boost C++ Library
miniupnpc UPnP Support Optional firewall-jumping support miniupnpc UPnP Support Optional firewall-jumping support
libqrencode QRCode generation Optional QRCode generation
miniupnpc may be used for UPnP port mapping. It can be downloaded from miniupnpc may be used for UPnP port mapping. It can be downloaded from
http://miniupnp.tuxfamily.org/files/. UPnP support is compiled in and http://miniupnp.tuxfamily.org/files/. UPnP support is compiled in and
@ -37,6 +38,12 @@ turned off by default. Set USE_UPNP to a different value to control this:
USE_UPNP=0 (the default) UPnP support turned off by default at runtime USE_UPNP=0 (the default) UPnP support turned off by default at runtime
USE_UPNP=1 UPnP support turned on by default at runtime USE_UPNP=1 UPnP support turned on by default at runtime
libqrencode may be used for QRCode image generation. It can be downloaded
from http://fukuchi.org/works/qrencode/index.html.en, or installed via
your package manager. Set USE_QRCODE to control this:
USE_QRCODE=0 (the default) No QRCode support - libarcode not required
USE_QRCODE=1 QRCode support enabled
Licenses of statically linked libraries: Licenses of statically linked libraries:
Berkeley DB New BSD license with additional requirement that linked Berkeley DB New BSD license with additional requirement that linked
software must be free open source software must be free open source
@ -50,7 +57,6 @@ Versions used in this release:
Boost 1.37 Boost 1.37
miniupnpc 1.6 miniupnpc 1.6
Dependency Build Instructions: Ubuntu & Debian Dependency Build Instructions: Ubuntu & Debian
---------------------------------------------- ----------------------------------------------
sudo apt-get install build-essential sudo apt-get install build-essential

4
src/makefile.osx vendored

@ -96,6 +96,10 @@ else
endif endif
endif endif
ifdef USE_QRCODE
DEFS += -DUSE_QRCODE=$(USE_QRCODE)
LIBS += -lqrencode
endif
all: bitcoind all: bitcoind

30
src/qt/addressbookpage.cpp

@ -10,6 +10,10 @@
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#ifdef USE_QRCODE
#include "qrcodedialog.h"
#endif
AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::AddressBookPage), ui(new Ui::AddressBookPage),
@ -25,6 +29,10 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
ui->deleteButton->setIcon(QIcon()); ui->deleteButton->setIcon(QIcon());
#endif #endif
#ifndef USE_QRCODE
ui->showQRCode->setVisible(false);
#endif
switch(mode) switch(mode)
{ {
case ForSending: case ForSending:
@ -169,10 +177,12 @@ void AddressBookPage::selectionChanged()
break; break;
} }
ui->copyToClipboard->setEnabled(true); ui->copyToClipboard->setEnabled(true);
ui->showQRCode->setEnabled(true);
} }
else else
{ {
ui->deleteButton->setEnabled(false); ui->deleteButton->setEnabled(false);
ui->showQRCode->setEnabled(false);
ui->copyToClipboard->setEnabled(false); ui->copyToClipboard->setEnabled(false);
} }
} }
@ -227,3 +237,23 @@ void AddressBookPage::exportClicked()
QMessageBox::Abort, QMessageBox::Abort); QMessageBox::Abort, QMessageBox::Abort);
} }
} }
void AddressBookPage::on_showQRCode_clicked()
{
#ifdef USE_QRCODE
QTableView *table = ui->tableView;
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
QRCodeDialog *d;
foreach (QModelIndex index, indexes)
{
QString address = index.data().toString(),
label = index.sibling(index.row(), 0).data().toString(),
title = QString("%1 << %2 >>").arg(label).arg(address);
QRCodeDialog *d = new QRCodeDialog(title, address, label, tab == ReceivingTab, this);
d->show();
}
#endif
}

1
src/qt/addressbookpage.h

@ -54,6 +54,7 @@ private slots:
void on_newAddressButton_clicked(); void on_newAddressButton_clicked();
void on_copyToClipboard_clicked(); void on_copyToClipboard_clicked();
void selectionChanged(); void selectionChanged();
void on_showQRCode_clicked();
}; };
#endif // ADDRESSBOOKDIALOG_H #endif // ADDRESSBOOKDIALOG_H

1
src/qt/bitcoin.qrc

@ -41,6 +41,7 @@
<qresource prefix="/images"> <qresource prefix="/images">
<file alias="about">res/images/about.png</file> <file alias="about">res/images/about.png</file>
<file alias="splash">res/images/splash2.jpg</file> <file alias="splash">res/images/splash2.jpg</file>
<file alias="qrcode">res/images/qrcode.png</file>
</qresource> </qresource>
<qresource prefix="/movies"> <qresource prefix="/movies">
<file alias="update_spinner">res/movies/update_spinner.mng</file> <file alias="update_spinner">res/movies/update_spinner.mng</file>

11
src/qt/forms/addressbookpage.ui

@ -79,6 +79,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="showQRCode">
<property name="text">
<string>Show &amp;QR Code</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/images/qrcode</normaloff>:/images/qrcode</iconset>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="deleteButton"> <widget class="QPushButton" name="deleteButton">
<property name="toolTip"> <property name="toolTip">

213
src/qt/forms/qrcodedialog.ui

@ -0,0 +1,213 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QRCodeDialog</class>
<widget class="QDialog" name="QRCodeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>404</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="lblQRCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>300</height>
</size>
</property>
<property name="text">
<string>QR Code</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="chkReq">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Request Payment</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblAm1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Amount:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnReqAmount</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lnReqAmount">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblAm2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>BTC</string>
</property>
<property name="buddy">
<cstring>lnReqAmount</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Label:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnLabel</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lnLabel">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Message:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnMessage</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lnMessage">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnSaveAs">
<property name="text">
<string>&amp;Save As...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>chkReq</sender>
<signal>clicked(bool)</signal>
<receiver>lnReqAmount</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>92</x>
<y>285</y>
</hint>
<hint type="destinationlabel">
<x>98</x>
<y>311</y>
</hint>
</hints>
</connection>
</connections>
</ui>

106
src/qt/qrcodedialog.cpp

@ -0,0 +1,106 @@
#include "qrcodedialog.h"
#include "ui_qrcodedialog.h"
#include <QPixmap>
#include <QUrl>
#include <QFileDialog>
#include <QDesktopServices>
#include <QDebug>
#include <qrencode.h>
#define EXPORT_IMAGE_SIZE 256
QRCodeDialog::QRCodeDialog(const QString &title, const QString &addr, const QString &label, bool enableReq, QWidget *parent) :
QDialog(parent),
ui(new Ui::QRCodeDialog),
address(addr)
{
ui->setupUi(this);
setWindowTitle(title);
setAttribute(Qt::WA_DeleteOnClose);
ui->chkReq->setVisible(enableReq);
ui->lnReqAmount->setVisible(enableReq);
ui->lblAm1->setVisible(enableReq);
ui->lblAm2->setVisible(enableReq);
ui->lnLabel->setText(label);
genCode();
}
QRCodeDialog::~QRCodeDialog()
{
delete ui;
}
void QRCodeDialog::genCode() {
QString uri = getURI();
//qDebug() << "Encoding:" << uri.toUtf8().constData();
QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
myImage.fill(0xffffff);
unsigned char *p = code->data;
for(int y = 0; y < code->width; y++) {
for(int x = 0; x < code->width; x++) {
myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
p++;
}
}
QRcode_free(code);
ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
}
QString QRCodeDialog::getURI() {
QString ret = QString("bitcoin:%1").arg(address);
int paramCount = 0;
if(ui->chkReq->isChecked() && ui->lnReqAmount->text().isEmpty() == false) {
bool ok= false;
double amount = ui->lnReqAmount->text().toDouble(&ok);
if(ok) {
ret += QString("?amount=%1X8").arg(ui->lnReqAmount->text());
paramCount++;
}
}
if(ui->lnLabel->text().isEmpty() == false) {
QString lbl(QUrl::toPercentEncoding(ui->lnLabel->text()));
ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl);
paramCount++;
}
if(ui->lnMessage->text().isEmpty() == false) {
QString msg(QUrl::toPercentEncoding(ui->lnMessage->text()));
ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg);
paramCount++;
}
return ret;
}
void QRCodeDialog::on_lnReqAmount_textChanged(const QString &) {
genCode();
}
void QRCodeDialog::on_lnLabel_textChanged(const QString &) {
genCode();
}
void QRCodeDialog::on_lnMessage_textChanged(const QString &) {
genCode();
}
void QRCodeDialog::on_btnSaveAs_clicked()
{
QString fn = QFileDialog::getSaveFileName(this, "Save Image...", QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation), "Images (*.png)");
if(!fn.isEmpty()) {
myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn);
}
}
void QRCodeDialog::on_chkReq_toggled(bool)
{
genCode();
}

37
src/qt/qrcodedialog.h

@ -0,0 +1,37 @@
#ifndef QRCODEDIALOG_H
#define QRCODEDIALOG_H
#include <QDialog>
#include <QImage>
namespace Ui {
class QRCodeDialog;
}
class QRCodeDialog : public QDialog
{
Q_OBJECT
public:
explicit QRCodeDialog(const QString &title, const QString &address, const QString &label, bool allowReq, QWidget *parent = 0);
~QRCodeDialog();
private slots:
void on_lnReqAmount_textChanged(const QString &arg1);
void on_lnLabel_textChanged(const QString &arg1);
void on_lnMessage_textChanged(const QString &arg1);
void on_btnSaveAs_clicked();
void on_chkReq_toggled(bool checked);
private:
Ui::QRCodeDialog *ui;
QImage myImage;
QString getURI();
QString address;
void genCode();
};
#endif // QRCODEDIALOG_H

BIN
src/qt/res/images/qrcode.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Loading…
Cancel
Save