kivy: use camera
This commit is contained in:
parent
3c1d6fab69
commit
644cb871f5
|
@ -16,3 +16,6 @@ then you need to rebuild the distribution. To do so:
|
|||
Note:
|
||||
python-for-android must be patched with:
|
||||
git pull git@github.com:denys-duchier/python-for-android.git fix-recursive-delete
|
||||
|
||||
|
||||
export P4A_pyjnius_DIR=local_clone
|
||||
|
|
|
@ -35,7 +35,7 @@ Factory.register('InstallWizard',
|
|||
Factory.register('InfoBubble', module='electrum_gui.kivy.uix.dialogs')
|
||||
Factory.register('OutputList', module='electrum_gui.kivy.uix.dialogs')
|
||||
Factory.register('OutputItem', module='electrum_gui.kivy.uix.dialogs')
|
||||
|
||||
Factory.register('QrScannerDialog', module='electrum_gui.kivy.uix.dialogs.qr_scanner')
|
||||
|
||||
|
||||
#from kivy.core.window import Window
|
||||
|
@ -241,12 +241,15 @@ class ElectrumWindow(App):
|
|||
self.show_error("invoice error:" + pr.error)
|
||||
self.send_screen.do_clear()
|
||||
|
||||
def on_qr(self, data):
|
||||
def on_qr(self, d, data):
|
||||
from electrum.bitcoin import base_decode, is_address
|
||||
if is_address(data):
|
||||
self.set_URI(data)
|
||||
return
|
||||
if data.startswith('bitcoin:'):
|
||||
self.set_URI(data)
|
||||
return
|
||||
# try to decode transaction
|
||||
from electrum.bitcoin import base_decode
|
||||
from electrum.transaction import Transaction
|
||||
try:
|
||||
text = base_decode(data, None, base=43).encode('hex')
|
||||
|
@ -307,6 +310,17 @@ class ElectrumWindow(App):
|
|||
popup.open()
|
||||
|
||||
def scan_qr(self, on_complete):
|
||||
self.scan_qr_android(on_complete)
|
||||
|
||||
def scan_qr_android(self, on_complete):
|
||||
dlg = Cache.get('electrum_widgets', 'QrScannerDialog')
|
||||
if not dlg:
|
||||
dlg = Factory.QrScannerDialog()
|
||||
Cache.append('electrum_widgets', 'QrScannerDialog', dlg)
|
||||
dlg.bind(on_complete=on_complete)
|
||||
dlg.open()
|
||||
|
||||
def scan_qr_zxing(self, on_complete):
|
||||
if platform != 'android':
|
||||
return
|
||||
from jnius import autoclass
|
||||
|
@ -555,8 +569,8 @@ class ElectrumWindow(App):
|
|||
@profiler
|
||||
def update_wallet(self, *dt):
|
||||
self._trigger_update_status()
|
||||
#if self.wallet.up_to_date or not self.network or not self.network.is_connected():
|
||||
self.update_tabs()
|
||||
if self.wallet.up_to_date or not self.network or not self.network.is_connected():
|
||||
self.update_tabs()
|
||||
|
||||
@profiler
|
||||
def notify_transactions(self, *dt):
|
||||
|
|
|
@ -244,6 +244,19 @@ class AndroidCamera(Widget):
|
|||
self._holder.pos = pos
|
||||
|
||||
|
||||
from electrum.util import profiler
|
||||
|
||||
use_camera = True
|
||||
if use_camera:
|
||||
from kivy.uix.camera import Camera
|
||||
from kivy.clock import Clock
|
||||
from PIL import Image as PILImage
|
||||
class MyCamera(Camera):
|
||||
def start(self):
|
||||
self.play = True
|
||||
def stop(self):
|
||||
self.play = False
|
||||
|
||||
class ScannerAndroid(ScannerBase):
|
||||
'''Widget that use the AndroidCamera and zbar to detect qrcode.
|
||||
When found, the `symbols` will be updated
|
||||
|
@ -251,10 +264,15 @@ class ScannerAndroid(ScannerBase):
|
|||
|
||||
def __init__(self, **kwargs):
|
||||
super(ScannerAndroid, self).__init__(**kwargs)
|
||||
self._camera = AndroidCamera(
|
||||
if use_camera:
|
||||
self._camera = MyCamera(resolution=self.camera_size)
|
||||
Clock.schedule_interval(self._detect_qrcode_frame2, 1)
|
||||
else:
|
||||
self._camera = AndroidCamera(
|
||||
size=self.camera_size,
|
||||
size_hint=(None, None))
|
||||
self._camera.bind(on_preview_frame=self._detect_qrcode_frame)
|
||||
self._camera.bind(on_preview_frame=self._detect_qrcode_frame)
|
||||
|
||||
self.add_widget(self._camera)
|
||||
|
||||
# create a scanner used for detecting qrcode
|
||||
|
@ -264,6 +282,7 @@ class ScannerAndroid(ScannerBase):
|
|||
self._scanner.setConfig(0, Config.X_DENSITY, 3)
|
||||
self._scanner.setConfig(0, Config.Y_DENSITY, 3)
|
||||
|
||||
|
||||
def start(self):
|
||||
self._camera.start()
|
||||
|
||||
|
@ -271,24 +290,36 @@ class ScannerAndroid(ScannerBase):
|
|||
self._camera.stop()
|
||||
|
||||
def _detect_qrcode_frame(self, instance, camera, data):
|
||||
# the image we got by default from a camera is using the NV21 format
|
||||
# zbar only allow Y800/GREY image, so we first need to convert,
|
||||
# then start the detection on the image
|
||||
if not self.get_root_window():
|
||||
self.stop()
|
||||
return
|
||||
parameters = camera.getParameters()
|
||||
size = parameters.getPreviewSize()
|
||||
barcode = Image(size.width, size.height, 'NV21')
|
||||
self.check_image(size.width, size.height, data)
|
||||
|
||||
def _detect_qrcode_frame2(self, *args):
|
||||
if not self._camera.play:
|
||||
return
|
||||
tex = self._camera.texture
|
||||
if not tex:
|
||||
return
|
||||
im = PILImage.fromstring('RGBA', tex.size, tex.pixels)
|
||||
im = im.convert('L')
|
||||
self.check_image(tex.size[0], tex.size[1], im.tostring())
|
||||
|
||||
@profiler
|
||||
def check_image(self, width, height, data):
|
||||
print "zzz", width, height, len(data)
|
||||
# the image we got by default from a camera is using the rgba format
|
||||
# zbar only allow Y800/GREY image, so we first need to convert,
|
||||
# then start the detection on the image
|
||||
barcode = Image(width, height, 'NV21')
|
||||
barcode.setData(data)
|
||||
barcode = barcode.convert('Y800')
|
||||
|
||||
result = self._scanner.scanImage(barcode)
|
||||
|
||||
if result == 0:
|
||||
self.symbols = []
|
||||
return
|
||||
|
||||
# we detected qrcode! extract and dispatch them
|
||||
symbols = []
|
||||
it = barcode.getSymbols().iterator()
|
||||
|
@ -301,9 +332,9 @@ class ScannerAndroid(ScannerBase):
|
|||
count=symbol.getCount(),
|
||||
bounds=symbol.getBounds())
|
||||
symbols.append(qrcode)
|
||||
|
||||
self.symbols = symbols
|
||||
|
||||
|
||||
'''
|
||||
# can't work, due to the overlay.
|
||||
def on_symbols(self, instance, value):
|
||||
|
|
|
@ -11,8 +11,8 @@ class QrScannerDialog(Factory.AnimatedPopup):
|
|||
def on_symbols(self, instance, value):
|
||||
instance.stop()
|
||||
self.dismiss()
|
||||
uri = App.get_running_app().decode_uri(value[0].data)
|
||||
self.dispatch('on_complete', uri)
|
||||
data = value[0].data
|
||||
self.dispatch('on_complete', data)
|
||||
|
||||
def on_complete(self, x):
|
||||
''' Default Handler for on_complete event.
|
||||
|
@ -30,10 +30,10 @@ Builder.load_string('''
|
|||
size_hint: None, None
|
||||
size: '340dp', '290dp'
|
||||
pos_hint: {'center_y': .53}
|
||||
separator_color: .89, .89, .89, 1
|
||||
separator_height: '1.2dp'
|
||||
title_color: .437, .437, .437, 1
|
||||
background: 'atlas://gui/kivy/theming/light/dialog'
|
||||
#separator_color: .89, .89, .89, 1
|
||||
#separator_height: '1.2dp'
|
||||
#title_color: .437, .437, .437, 1
|
||||
#background: 'atlas://gui/kivy/theming/light/dialog'
|
||||
on_activate:
|
||||
qrscr.start()
|
||||
qrscr.size = self.size
|
||||
|
|
|
@ -77,7 +77,7 @@ SendScreen:
|
|||
IconButton:
|
||||
id: qr
|
||||
size_hint: 0.6, 1
|
||||
on_release: app.scan_qr(on_complete=app.on_qr)
|
||||
on_release: Clock.schedule_once(lambda dt: app.scan_qr(on_complete=app.on_qr))
|
||||
icon: 'atlas://gui/kivy/theming/light/camera'
|
||||
Button:
|
||||
text: _('Paste')
|
||||
|
|
Loading…
Reference in New Issue