tkivy: remove qr_scanner - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 167088e22a422366297d26eb764795eb37e0c0f7 DIR parent 1f1dbaf523ee02eb3960f5ba2182a4bb8b9390ff HTML Author: ThomasV <thomasv@electrum.org> Date: Thu, 17 Mar 2016 09:55:42 +0100 kivy: remove qr_scanner Diffstat: M gui/kivy/main_window.py | 6 ------ D gui/kivy/qr_scanner/__init__.py | 60 ------------------------------- D gui/kivy/qr_scanner/scanner_androi… | 390 ------------------------------- D gui/kivy/qr_scanner/scanner_camera… | 96 ------------------------------- 4 files changed, 0 insertions(+), 552 deletions(-) --- DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py t@@ -35,7 +35,6 @@ 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 t@@ -191,7 +190,6 @@ class ElectrumWindow(App): # initialize variables self._clipboard = Clipboard self.info_bubble = None - self.qrscanner = None self.nfcscanner = None self.tabs = None self.is_exit = False t@@ -610,15 +608,11 @@ class ElectrumWindow(App): def on_pause(self): # pause nfc - if self.qrscanner: - self.qrscanner.stop() if self.nfcscanner: self.nfcscanner.nfc_disable() return True def on_resume(self): - if self.qrscanner and qrscanner.get_parent_window(): - self.qrscanner.start() if self.nfcscanner: self.nfcscanner.nfc_enable() DIR diff --git a/gui/kivy/qr_scanner/__init__.py b/gui/kivy/qr_scanner/__init__.py t@@ -1,60 +0,0 @@ -'''QrScanner Base Abstract implementation -''' - -__all__ = ('ScannerBase', 'QRScanner') - -from collections import namedtuple - -from kivy.uix.anchorlayout import AnchorLayout -from kivy.core import core_select_lib -from kivy.metrics import dp -from kivy.properties import ListProperty, BooleanProperty -from kivy.factory import Factory - - -class ScannerBase(AnchorLayout): - ''' Base implementation for camera based scanner - ''' - camera_size = ListProperty([320, 240] if dp(1) < 2 else [640, 480]) - - symbols = ListProperty([]) - - # XXX can't work now, due to overlay. - show_bounds = BooleanProperty(False) - - running = BooleanProperty(False) - - Qrcode = namedtuple('Qrcode', - ['type', 'data', 'bounds', 'quality', 'count']) - - def start(self): - pass - - def stop(self): - pass - - def on_symbols(self, instance, value): - #if self.show_bounds: - # self.update_bounds() - pass - - def update_bounds(self): - self.canvas.after.remove_group('bounds') - if not self.symbols: - return - with self.canvas.after: - Color(1, 0, 0, group='bounds') - for symbol in self.symbols: - x, y, w, h = symbol.bounds - x = self._camera.right - x - w - y = self._camera.top - y - h - Line(rectangle=[x, y, w, h], group='bounds') - - -# load QRCodeDetector implementation - -QRScanner = core_select_lib('qr_scanner', ( - ('android', 'scanner_android', 'ScannerAndroid'), - ('camera', 'scanner_camera', 'ScannerCamera')), False, 'electrum_gui.kivy') - -Factory.register('QRScanner', cls=QRScanner) DIR diff --git a/gui/kivy/qr_scanner/scanner_android.py b/gui/kivy/qr_scanner/scanner_android.py t@@ -1,390 +0,0 @@ -''' -Qrcode example application -========================== - -Author: Mathieu Virbel <mat@meltingrocks.com> - -License: -Copyright (c) 2013 Mathieu Virbel <mat@meltingrocks.com> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -Featuring: - -- Android camera initialization -- Show the android camera into a Android surface that act as an overlay -- New AndroidWidgetHolder that control any android view as an overlay -- New ZbarQrcodeDetector that use AndroidCamera / PreviewFrame + zbar to - detect Qrcode. - -''' - -__all__ = ('ScannerAndroid', ) - -from kivy.utils import platform -if platform != 'android': - raise ImportError - -from electrum_gui.kivy.qr_scanner import ScannerBase -from kivy.properties import ObjectProperty, NumericProperty -from kivy.uix.widget import Widget -from kivy.uix.anchorlayout import AnchorLayout -from kivy.graphics import Color, Line -from jnius import autoclass, PythonJavaClass, java_method, cast -from android.runnable import run_on_ui_thread - -# preload java classes -System = autoclass('java.lang.System') -System.loadLibrary('iconv') -PythonActivity = autoclass('org.renpy.android.PythonActivity') -Camera = autoclass('android.hardware.Camera') -ImageScanner = autoclass('net.sourceforge.zbar.ImageScanner') -Image = autoclass('net.sourceforge.zbar.Image') -Symbol = autoclass('net.sourceforge.zbar.Symbol') -Config = autoclass('net.sourceforge.zbar.Config') -SurfaceView = autoclass('android.view.SurfaceView') -LayoutParams = autoclass('android.view.ViewGroup$LayoutParams') -ImageFormat = autoclass('android.graphics.ImageFormat') -LinearLayout = autoclass('android.widget.LinearLayout') - - -class PreviewCallback(PythonJavaClass): - '''Interface used to get back the preview frame of the Android Camera - ''' - __javainterfaces__ = ('android.hardware.Camera$PreviewCallback', ) - - def __init__(self, callback): - super(PreviewCallback, self).__init__() - self.callback = callback - - @java_method('([BLandroid/hardware/Camera;)V') - def onPreviewFrame(self, data, camera): - self.callback(camera, data) - - -class SurfaceHolderCallback(PythonJavaClass): - '''Interface used to know exactly when the Surface used for the Android - Camera will be created and changed. - ''' - - __javainterfaces__ = ('android.view.SurfaceHolder$Callback', ) - - def __init__(self, callback): - super(SurfaceHolderCallback, self).__init__() - self.callback = callback - - @java_method('(Landroid/view/SurfaceHolder;III)V') - def surfaceChanged(self, surface, fmt, width, height): - self.callback(fmt, width, height) - - @java_method('(Landroid/view/SurfaceHolder;)V') - def surfaceCreated(self, surface): - pass - - @java_method('(Landroid/view/SurfaceHolder;)V') - def surfaceDestroyed(self, surface): - pass - - -class AndroidWidgetHolder(Widget): - '''Act as a placeholder for an Android widget. - It will automatically add / remove the android view depending if the widget - view is set or not. The android view will act as an overlay, so any graphics - instruction in this area will be covered by the overlay. - ''' - - view = ObjectProperty(allownone=True) - '''Must be an Android View - ''' - - def __init__(self, **kwargs): - self._old_view = None - from kivy.core.window import Window - self._window = Window - kwargs['size_hint'] = (None, None) - super(AndroidWidgetHolder, self).__init__(**kwargs) - - def on_view(self, instance, view): - if self._old_view is not None: - layout = cast(LinearLayout, self._old_view.getParent()) - layout.removeView(self._old_view) - self._old_view = None - - if view is None: - return - - activity = PythonActivity.mActivity - activity.addContentView(view, LayoutParams(*self.size)) - view.setZOrderOnTop(True) - view.setX(self.x) - view.setY(self._window.height - self.y - self.height) - self._old_view = view - - def on_size(self, instance, size): - if self.view: - params = self.view.getLayoutParams() - params.width = self.width - params.height = self.height - self.view.setLayoutParams(params) - self.view.setY(self._window.height - self.y - self.height) - - def on_x(self, instance, x): - if self.view: - self.view.setX(x) - - def on_y(self, instance, y): - if self.view: - self.view.setY(self._window.height - self.y - self.height) - - -class AndroidCamera(Widget): - '''Widget for controling an Android Camera. - ''' - - index = NumericProperty(0) - - __events__ = ('on_preview_frame', ) - - def __init__(self, **kwargs): - self._holder = None - self._android_camera = None - super(AndroidCamera, self).__init__(**kwargs) - self._holder = AndroidWidgetHolder(size=self.size, pos=self.pos) - self.add_widget(self._holder) - - @run_on_ui_thread - def stop(self): - self.running = False - if self._android_camera is None: - return - self._android_camera.setPreviewCallback(None) - self._android_camera.release() - self._android_camera = None - self._holder.view = None - - @run_on_ui_thread - def start(self): - self.running = True - if self._android_camera is not None: - return - - self._android_camera = Camera.open(self.index) - - # create a fake surfaceview to get the previewCallback working. - self._android_surface = SurfaceView(PythonActivity.mActivity) - surface_holder = self._android_surface.getHolder() - - # create our own surface holder to correctly call the next method when - # the surface is ready - self._android_surface_cb = SurfaceHolderCallback(self._on_surface_changed) - surface_holder.addCallback(self._android_surface_cb) - - # attach the android surfaceview to our android widget holder - self._holder.view = self._android_surface - - # set orientation - self._android_camera.setDisplayOrientation(90) - - def _on_surface_changed(self, fmt, width, height): - # internal, called when the android SurfaceView is ready - # FIXME if the size is not handled by the camera, it will failed. - params = self._android_camera.getParameters() - params.setPreviewSize(width, height) - self._android_camera.setParameters(params) - - # now that we know the camera size, we'll create 2 buffers for faster - # result (using Callback buffer approach, as described in Camera android - # documentation) - # it also reduce the GC collection - bpp = ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8. - buf = '\x00' * int(width * height * bpp) - self._android_camera.addCallbackBuffer(buf) - self._android_camera.addCallbackBuffer(buf) - - # create a PreviewCallback to get back the onPreviewFrame into python - self._previewCallback = PreviewCallback(self._on_preview_frame) - - # connect everything and start the preview - self._android_camera.setPreviewCallbackWithBuffer(self._previewCallback); - self._android_camera.setPreviewDisplay(self._android_surface.getHolder()) - self._android_camera.startPreview(); - - def _on_preview_frame(self, camera, data): - # internal, called by the PreviewCallback when onPreviewFrame is - # received - self.dispatch('on_preview_frame', camera, data) - # reintroduce the data buffer into the queue - self._android_camera.addCallbackBuffer(data) - - def on_preview_frame(self, camera, data): - pass - - def on_size(self, instance, size): - if self._holder: - self._holder.size = size - - def on_pos(self, instance, pos): - if self._holder: - 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 - ''' - - def __init__(self, **kwargs): - super(ScannerAndroid, self).__init__(**kwargs) - 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.add_widget(self._camera) - - # create a scanner used for detecting qrcode - self._scanner = ImageScanner() - self._scanner.setConfig(0, Config.ENABLE, 0) - self._scanner.setConfig(Symbol.QRCODE, Config.ENABLE, 1) - self._scanner.setConfig(0, Config.X_DENSITY, 3) - self._scanner.setConfig(0, Config.Y_DENSITY, 3) - - - def start(self): - self._camera.start() - - def stop(self): - self._camera.stop() - - def _detect_qrcode_frame(self, instance, camera, data): - if not self.get_root_window(): - self.stop() - return - parameters = camera.getParameters() - size = parameters.getPreviewSize() - 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() - while it.hasNext(): - symbol = it.next() - qrcode = ScannerAndroid.Qrcode( - type=symbol.getType(), - data=symbol.getData(), - quality=symbol.getQuality(), - 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): - if self.show_bounds: - self.update_bounds() - - def update_bounds(self): - self.canvas.after.remove_group('bounds') - if not self.symbols: - return - with self.canvas.after: - Color(1, 0, 0, group='bounds') - for symbol in self.symbols: - x, y, w, h = symbol.bounds - x = self._camera.right - x - w - y = self._camera.top - y - h - Line(rectangle=[x, y, w, h], group='bounds') - ''' - - -if __name__ == '__main__': - from kivy.lang import Builder - from kivy.app import App - - qrcode_kv = ''' -BoxLayout: - orientation: 'vertical' - - ZbarQrcodeDetector: - id: detector - - Label: - text: '\\n'.join(map(repr, detector.symbols)) - size_hint_y: None - height: '100dp' - - BoxLayout: - size_hint_y: None - height: '48dp' - - Button: - text: 'Scan a qrcode' - on_release: detector.start() - Button: - text: 'Stop detection' - on_release: detector.stop() -''' - - class QrcodeExample(App): - def build(self): - return Builder.load_string(qrcode_kv) - - QrcodeExample().run() DIR diff --git a/gui/kivy/qr_scanner/scanner_camera.py b/gui/kivy/qr_scanner/scanner_camera.py t@@ -1,96 +0,0 @@ -from kivy.uix.camera import Camera -from kivy.clock import Clock -from kivy.utils import platform - -from electrum_gui.kivy.qr_scanner import ScannerBase - -import iconv - -try: - from zbar import ImageScanner, Config, Image, Symbol -except ImportError: - raise SystemError('unable to import zbar please make sure you have' - ' it installed.\nFor mac osx: `brew install zbar then\n`' - '`pip install https://github.com/npinchot/zbar/archive/d3c1611ad2411fbdc3e79eb96ca704a63d30ae69.zip`') -try: - from PIL import Image as PILImage -except ImportError: - raise SystemError('unable to import Pil/pillow' - ' please install one of the two.') - -__all__ = ('ScannerCamera', ) - -class ScannerCamera(ScannerBase): - '''Widget that use the kivy.uix.camera.Camera and zbar to detect - qrcode. When found, the `symbols` will be updated - ''' - - def __init__(self, **kwargs): - super(ScannerCamera, self).__init__(**kwargs) - self._camera = None - # create a scanner used for detecting qrcode - self._scanner = ImageScanner() - self._scanner.parse_config('enable') - #self._scanner.setConfig(Symbol.QRCODE, Config.ENABLE, 1) - #self._scanner.setConfig(0, Config.X_DENSITY, 3) - #self._scanner.setConfig(0, Config.Y_DENSITY, 3) - - def start(self): - if not self._camera: - self._camera = Camera( - resolution=self.camera_size, - size_hint=(None, None)) - self.add_widget(self._camera) - self.bind(size=self._camera.setter('size')) - self.bind(pos=self._camera.setter('pos')) - else: - self._camera._camera.init_camera() - self._camera.play = True - Clock.schedule_interval(self._detect_qrcode_frame, 1/15) - - def stop(self): - if not self._camera: - return - self._camera.play = False - Clock.unschedule(self._detect_qrcode_frame) - # TODO: testing for various platforms(windows, mac) - if platform == 'linux': - self._camera._camera._pipeline.set_state(1) - #self._camera = None - - def _detect_qrcode_frame(self, *args): - # 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 - if not self.get_root_window(): - self.stop() - return - cam = self._camera - tex = cam.texture - if not tex: - return - im = PILImage.fromstring('RGBA', tex.size, tex.pixels) - im = im.convert('L') - barcode = Image(tex.size[0], - tex.size[1], 'Y800', im.tostring()) - - result = self._scanner.scan(barcode) - - if result == 0: - self.symbols = [] - del(barcode) - return - - # we detected qrcode! extract and dispatch them - symbols = [] - for symbol in barcode.symbols: - qrcode = ScannerCamera.Qrcode( - type=symbol.type, - data=symbol.data, - quality=symbol.quality, - count=symbol.count, - bounds=symbol.location) - symbols.append(qrcode) - - self.symbols = symbols - del(barcode)