Exemple #1
0
 def __init__(self, debug_barcodes):
     if not gouda:
         raise InselectError('Barcode decoding not available')
     elif not DATAMATRIX_ENGINE:
         raise InselectError('No datamatrix engine available')
     else:
         self.engine = DATAMATRIX_ENGINE()
         gouda.util.DEBUG_PRINT = debug_barcodes
Exemple #2
0
 def __init__(self, path):
     path = Path(path)
     if not path.is_file():
         raise InselectError('Image file [{0}] does not exist'.format(str(path)))
     else:
         self._path = path
         self._array = None
Exemple #3
0
    def __call__(self, progress):
        """
        """
        debug_print('BarcodePlugin.__call__')

        if InliteEngine.available():
            engine = InliteEngine(datamatrix=True)
        elif LibDMTXEngine.available():
            engine = LibDMTXEngine()
        else:
            raise InselectError('No barcode decoding engine available')

        progress('Loading full-res image')
        image_array = self.document.scanned.array

        items = self.document.items
        for index, item, crop in izip(count(), items, self.document.crops):
            msg = u'Reading barcodes in box {0} of {1}'.format(1 + index, len(items))
            progress(msg)
            barcodes = self._decode_barcodes(engine, crop, progress)
            if barcodes:
                debug_print('Crop [{0}] - found [{1}]'.format(index, barcodes))

                # TODO LH This mapping to come from metadata config?
                item['fields']['catalogNumber'] = barcodes
            else:
                debug_print('Crop [{0}] - no barcodes'.format(index))

        self.items = items

        debug_print('BarcodePlugin.__call__ exiting. [{0}] boxes'.format(len(items)))
Exemple #4
0
    def open_file(self, path=None):
        """Opens path, which can be None, the path to an inselect document or
        the path to an image file. If None, the user is prompted to select a
        file.

        * If a .inselect file, the file is opened
        * If an image file for which a .inselect document already exists, the
        .inselect file is opened
        * If a _thumbnail.jpg file corresponding to an existing .inselect file,
        the .inselect file is opened
        * If an image file, a new .inselect file is created and opened
        """
        debug_print(u'MainWindow.open_file [{0}]'.format(path))

        if not path:
            folder = QSettings().value(
                'working_directory',
                QDesktopServices.storageLocation(
                    QDesktopServices.DocumentsLocation))

            filter = u'Inselect documents (*{0});;Images ({1})'
            filter = filter.format(InselectDocument.EXTENSION,
                                   u' '.join(IMAGE_PATTERNS))
            path, selectedFilter = QtGui.QFileDialog.getOpenFileName(
                self, "Open", folder, filter)

        if path:
            # Will be None if user cancelled getOpenFileName
            if not self.close_document():
                # User does not want to close the existing document
                pass
            else:
                path = Path(path)

                if path.suffix in IMAGE_SUFFIXES:
                    # Compute the path to the inselect document (which may or
                    # may not already exist) of the image file
                    doc_of_image = path.name.replace(
                        InselectDocument.THUMBNAIL_SUFFIX, u'')
                    doc_of_image = path.parent / doc_of_image
                    doc_of_image = doc_of_image.with_suffix(
                        InselectDocument.EXTENSION)
                else:
                    doc_of_image = None

                if InselectDocument.EXTENSION == path.suffix:
                    # Open the .inselect document
                    debug_print('Opening inselect document [{0}]'.format(path))
                    self.open_document(path)
                elif doc_of_image and doc_of_image.is_file():
                    # An image file corresponding to an existing .inselect file
                    msg = u'Opening inselect document [{0}] of thumbnail [{1}]'
                    debug_print(msg.format(doc_of_image, path))
                    self.open_document(doc_of_image)
                elif path.suffix in IMAGE_SUFFIXES:
                    msg = u'Creating new inselect document for image [{0}]'
                    debug_print(msg.format(path))
                    self.new_document(path)
                else:
                    raise InselectError('Unknown file type [{0}]'.format(path))
 def scene_box_added(self, rect):
     """The user added a box
     """
     m = self.model()
     row = len(self._rows)
     if not m.insertRow(row):
         raise InselectError('Could not insert row')
     else:
         # Cumbersome conversion to ints
         rect = QRect(rect.left(), rect.top(), rect.width(), rect.height())
         if not m.setData(m.index(row, 0), rect, RectRole):
             raise InselectError('Could not set rect')
         else:
             # Select the new box
             self.scene.clearSelection()
             item = next(self.items_of_rows([row]))
             item.setSelected(True)
             item.update()
 def __init__(self, document, parent):
     super(BarcodePlugin, self).__init__()
     try:
         import gouda.strategies.roi.roi  # noqa
         import gouda.strategies.resize  # noqa
     except ImportError:
         raise InselectError('Barcode decoding is not available')
     else:
         self.document = document
         self.parent = parent
def main(args=None):
    if args is None:
        args = sys.argv[1:]

    # Private import to avoid top-level import of cv2 (via gouda), which
    # would make the script slower to start and potentially break if
    # frozen on Windows (see call to fix_frozen_dll_path below).
    try:
        import gouda
    except ImportError:
        gouda = engine_options = None
    else:
        from gouda.engines.options import engine_options
        from gouda.strategies.resize import resize
        from gouda.strategies.roi.roi import roi

    if not gouda:
        raise InselectError('Barcode decoding not available')
    options = engine_options()
    if not options:
        raise InselectError('No barcode reading engines are available')

    parser = argparse.ArgumentParser(
        description='Reads barcodes within boxes, overwriting existing values')
    parser.add_argument('--debug', action='store_true')
    parser.add_argument('--debug-barcodes', action='store_true')
    parser.add_argument('-v',
                        '--version',
                        action='version',
                        version='%(prog)s ' + inselect.__version__)
    parser.add_argument("dir",
                        type=Path,
                        help='Directory containing inselect documents')
    parser.add_argument('engine',
                        choices=sorted(options.keys()),
                        help='The barcode reading engine to use')
    args = parser.parse_args(args)

    inselect.lib.utils.DEBUG_PRINT = args.debug
    gouda.util.DEBUG_PRINT = args.debug_barcodes
    engine = options[args.engine]()
    read_barcodes(engine, args.dir, strategies=(resize, roi))
Exemple #8
0
 def save_crops(self, normalised, paths, progress=None):
     "Saves crops given in normalised to paths."
     # TODO Copy EXIF tags?
     # TODO Make read-only?
     for index, crop, path in izip(count(), self.crops(normalised), paths):
         if progress:
             progress('Writing crop {0}'.format(1 + index))
         if not cv2.imwrite(str(path), crop):
             raise InselectError('Unable to write crop [{0}]'.format(path))
         else:
             debug_print('Wrote crop [{0}]'.format(path))
Exemple #9
0
 def array(self):
     """ Lazy-load np.array of the image
     """
     if self._array is None:
         p = str(self._path)
         debug_print('Reading from image file [{0}]'.format(p))
         image = cv2.imread(p)
         if image is None:
             raise InselectError('[{0}] could not be read as an image'.format(p))
         else:
             self._array = image
     return self._array
Exemple #10
0
def load_engine():
    """Returns an instance of the user's choice of barcode reading engine
    """
    try:
        from gouda.engines import InliteEngine, LibDMTXEngine, ZbarEngine
    except ImportError:
        raise InselectError('Barcode decoding is not available')
    else:
        settings = current_settings()
        engine = settings['engine']
        if 'libdmtx' == engine:
            return LibDMTXEngine()
        elif 'zbar' == engine:
            return ZbarEngine()
        elif 'inlite' == engine:
            return InliteEngine(settings['inlite-format'])
        else:
            raise ValueError(
                'Unrecognised barcode reader [{0}]'.format(engine))
Exemple #11
0
def ingest_from_directory(inbox, docs):
    """Ingest images from the directory given by inbox to the directory given
    by docs
    """
    inbox, docs = Path(inbox), Path(docs)
    if not inbox.is_dir():
        raise InselectError(
            'Inbox directory [{0}] does not exist'.format(inbox))

    if not docs.is_dir():
        print('Create document directory [{0}]'.format(docs))
        docs.mkdir(parents=True)

    # TODO LH Case insensitive matching
    for source in apply(chain, [inbox.glob(p) for p in IMAGE_PATTERNS]):
        try:
            ingest_image(source, docs)
        except Exception:
            print('Error ingesting [{0}]'.format(source))
            traceback.print_exc()
Exemple #12
0
    def new_document(self, path):
        """Creates and opens a new inselect document for the scanned image
        given in path
        """
        debug_print('MainWindow.new_document [{0}]'.format(path))

        path = Path(path)
        if not path.is_file():
            raise InselectError(
                u'Image file [{0}] does not exist'.format(path))
        else:
            # Callable for worker thread
            class NewDoc(object):
                def __init__(self, image):
                    self.image = image

                def __call__(self, progress):
                    progress('Creating thumbnail of scanned image')
                    doc = ingest_image(self.image, self.image.parent)
                    self.document_path = doc.document_path

            self.run_in_worker(NewDoc(path), 'New document',
                               self.new_document_finished)
Exemple #13
0
def ingest_from_directory(
        inbox,
        docs,
        thumbnail_width_pixels=InselectDocument.THUMBNAIL_DEFAULT_WIDTH,
        cookie_cutter=None):
    """Ingest images from the directory given by inbox to the directory given
    by docs
    """
    inbox, docs = Path(inbox), Path(docs)
    cookie_cutter = Path(cookie_cutter) if cookie_cutter else None
    if not inbox.is_dir():
        raise InselectError(
            'Inbox directory [{0}] does not exist'.format(inbox))

    if not docs.is_dir():
        print('Create document directory [{0}]'.format(docs))
        docs.mkdir(parents=True)

    if cookie_cutter:
        cookie_cutter = CookieCutter.load(cookie_cutter)

    for source in (p for p in inbox.iterdir()
                   if IMAGE_SUFFIXES_RE.match(p.name)):
        print('Ingesting [{0}]'.format(source))
        try:
            ingest_image(source,
                         docs,
                         thumbnail_width_pixels=thumbnail_width_pixels,
                         cookie_cutter=cookie_cutter)
        except KeyboardInterrupt:
            raise
        except Exception:
            print('Error ingesting [{0}]'.format(source))
            traceback.print_exc()
        else:
            print('Ingested [{0}]'.format(source))
Exemple #14
0
 def __new__(cls, left, top, width, height):
     if left < 0 or top < 0 or width <= 0 or height <= 0:
         raise InselectError('Bad rectangle')
     else:
         return super(Rect, cls).__new__(cls, left, top, width, height)
Exemple #15
0
 def __init__(self, document, parent):
     if not gouda:
         raise InselectError('Barcode decoding is not available')
     else:
         self.document = document
Exemple #16
0
 def validate_in_bounds(self, boxes):
     h, w = self.array.shape[:2]
     for left, top, width, height in boxes:
         if not (left>=0 and top>=0 and left<w and top<h and width>0 and
                 left+width<=w and height>0 and top+height<=h):
             raise InselectError('One or more boxes are not in bounds')
Exemple #17
0
def validate_normalised(boxes):
    for l, t, w, h in boxes:
        if not (l >= 0 and t >= 0 and l <= 1 and t <= 1 and w > 0
                and l + w <= 1 and h > 0 and t + h <= 1):
            raise InselectError('One or more boxes are not normalised')