Exemple #1
0
    def _read(self, stream: Stream, version):
        self.color = stream.read_object('color')

        number_layers = stream.read_int('layers')
        for i in range(number_layers):
            stream.consume_padding()
            layer = stream.read_object('symbol layer {}/{}'.format(
                i + 1, number_layers))
            self.levels.extend([layer])

        # the next section varies in size. To handle this we jump forward to a known anchor
        # point, and then move back by a known amount

        # burn up to the 02
        stream.log('burning up to 02...')
        while not binascii.hexlify(stream.read(1)) == b'02':
            pass

        # jump back a known amount
        stream.rewind(8 * number_layers + 1)

        for l in self.levels:
            l.read_enabled(stream)
        for l in self.levels:
            l.read_locked(stream)
Exemple #2
0
    def read(self, stream: Stream, version):
        self.color = stream.read_object('color')

        self.unicode = stream.read_int('unicode')
        self.angle = stream.read_double('angle')
        self.size = stream.read_double('size')
        self.x_offset = stream.read_double('x offset')
        self.y_offset = stream.read_double('y offset')

        stream.read_double('unknown 1')
        stream.read_double('unknown 2')

        self.read_0d_terminator(stream)
        if binascii.hexlify(stream.read(2)) != b'ffff':
            raise UnreadableSymbolException('Expected ffff')

        self.font = stream.read_string('font name')

        # lot of unknown stuff
        stream.read_double('unknown 3')  # or object?
        stream.read_double('unknown 4')  # or object?
        if binascii.hexlify(stream.read(2)) != b'9001':
            raise UnreadableSymbolException('Expected 9001')

        stream.read(4)
        stream.read(6)

        # std OLE font .. maybe contains useful stuff like bold/etc, but these aren't exposed in ArcGIS anyway..
        self.std_font = stream.read_object('font')
Exemple #3
0
    def read(self, stream: Stream, version):
        stream.read_int('unknown')
        stream.read_int('unknown 2')

        self.file = stream.read_embedded_file('image')

        self.color_foreground = stream.read_object('color 1')
        self.color_background = stream.read_object('color 2')
        self.color_transparent = stream.read_object('color 3')

        self.angle = stream.read_double('angle')
        self.size = stream.read_double('size')
        self.x_offset = stream.read_double('x offset')
        self.y_offset = stream.read_double('y offset')

        stream.read_double('unknown')
        stream.read_double('unknown')

        stream.read_0d_terminator()
        self.swap_fb_gb = bool(stream.read_uchar('swap fgbg'))

        check = binascii.hexlify(stream.read(2))
        if check != b'ffff':
            raise UnreadableSymbolException(
                'Expected ffff at {}, got {}'.format(check,
                                                     hex(stream.tell() - 2)))

        # unknown
        stream.read(6)
Exemple #4
0
    def read(self, stream: Stream, version):
        if not stream.read_0d_terminator():
            raise UnreadableSymbolException('Could not find 0d terminator at {}'.format(hex(stream.tell() - 8)))

        # consume unused properties - MultiLayerMarkerSymbol implements IMarkerSymbol
        # so that the size/offsets/angle are required properties. But they aren't used
        # or exposed anywhere for MultiLayerMarkerSymbol
        _ = stream.read_double('unused marker size')
        _ = stream.read_double('unused marker x/y/offset or angle')
        _ = stream.read_double('unused marker x/y/offset or angle')
        _ = stream.read_double('unused marker x/y/offset or angle')
        _ = stream.read_object('unused color')

        self.halo = stream.read_int() == 1
        self.halo_size = stream.read_double('halo size')

        self.halo_symbol = stream.read_object('halo')

        # useful stuff
        number_layers = stream.read_int('layers')
        for i in range(number_layers):
            layer = stream.read_object('symbol layer {}/{}'.format(i + 1, number_layers))
            self.levels.extend([layer])

        for l in self.levels:
            l.read_enabled(stream)
        for l in self.levels:
            l.read_locked(stream)

        _ = stream.read_double('unknown size')
        _ = stream.read_double('unknown size')

        if version >= 3:
            for l in self.levels:
                l.read_tags(stream)
Exemple #5
0
    def read(self, stream: Stream, version):
        self.angle = stream.read_double('angle')
        self.cap = self.read_cap(stream)
        unknown = binascii.hexlify(stream.read(3))
        if unknown != b'000000':
            raise UnreadableSymbolException(
                'Differing unknown string {}'.format(unknown))
        self.join = self.read_join(stream)
        unknown = binascii.hexlify(stream.read(3))
        if unknown != b'000000':
            raise UnreadableSymbolException(
                'Differing unknown string {}'.format(unknown))
        self.width = stream.read_double('width')
        stream.read(1)
        self.offset = stream.read_double('offset')

        self.line = stream.read_object('line')

        self.color = stream.read_object('color')
        self.template = stream.read_object('template')

        self.decoration = stream.read_object('decoration')
        stream.read_0d_terminator()

        _ = stream.read_uchar('unknown char')
        _ = stream.read_double('unknown')
        _ = stream.read_double('unknown')
Exemple #6
0
    def read(self, stream: Stream, version):
        self.cap = self.read_cap(stream)
        stream.log('read cap of {}'.format(self.cap), 1)

        self.offset = stream.read_double('offset')
        self.pattern_marker = stream.read_object('pattern marker')
        self.template = stream.read_object('template')
        self.decoration = stream.read_object('decoration')

        self.read_0d_terminator(stream)
Exemple #7
0
    def read(self, stream: Stream, version):
        # first bit is either an entire LineSymbol or just a LineSymbolLayer
        outline = stream.read_object('outline')
        if outline is not None:
            if issubclass(outline.__class__, SymbolLayer):
                self.outline_layer = outline
            else:
                self.outline_symbol = outline

        self.color = stream.read_object('color')
        self.read_0d_terminator(stream)
Exemple #8
0
    def read(self, stream: Stream, version):
        self.color = stream.read_object('color')
        self.width = stream.read_double('width')

        self.line_type = self.read_line_type(stream)
        stream.log('read line type of {}'.format(self.line_type))
        self.read_0d_terminator(stream)
    def run_symbol_checks(self, path):
        """
        Checks all bin symbols against expectations
        """

        blobs = []
        for fn in os.listdir(path):
            file = os.path.join(path, fn)
            if os.path.isfile(file):
                blobs.append(file)

        for file in blobs:
            print(file)
            group, symbol_name = os.path.split(file)
            path, group = os.path.split(group)

            with open(file, 'rb') as f:
                expected_symbol = expected[group][symbol_name]
                if 'skip' in expected_symbol:
                    continue
                stream = Stream(f, debug=False)

                color = stream.read_object()

                self.assertEqual(color.to_dict(), expected_symbol['color'])
                self.assertEqual(color.model, expected_symbol['model'])
Exemple #10
0
    def read(self, stream: Stream, version):
        """
        Reads the decoration information
        """
        self.fixed_angle = not bool(stream.read_uchar())
        stream.log('detected {}'.format(
            'fixed angle' if self.fixed_angle else 'not fixed angle'))
        self.flip_first = bool(stream.read_uchar())
        stream.log('detected {}'.format(
            'flip first' if self.flip_first else 'no flip first'))
        self.flip_all = bool(stream.read_uchar())
        stream.log('detected {}'.format(
            'flip all' if self.flip_all else 'no flip all'))

        stream.read(2)  # unknown -- maybe includes position as ratio?

        self.marker = stream.read_object('marker')

        # next bit is the number of doubles coming next
        marker_number_positions = stream.read_uint('marker positions')

        # next bit is the positions themselves -- maybe we can infer this from the number of positions
        # alone. E.g. 2 positions = 0, 1. 3 positions = 0, 0.5, 1
        for _ in range(marker_number_positions):
            self.marker_positions.append(stream.read_double())
        stream.log('marker positions are {}'.format(self.marker_positions))
Exemple #11
0
    def _read(self, stream: Stream, version):
        number_layers = stream.read_uint('layer count')
        for i in range(number_layers):
            layer = stream.read_object('symbol layer {}/{}'.format(
                i + 1, number_layers))
            self.levels.extend([layer])

        # the next section varies in size. To handle this we jump forward to a known anchor
        # point, and then move back by a known amount

        # burn up to the 02
        stream.log('burning up to 02...')
        while not binascii.hexlify(stream.read(1)) == b'02':
            pass

        # jump back a known amount
        stream.rewind(8 * number_layers + 1)

        # TODO - replace the fragile bit above!
        #   stream.read(1)

        #   stream.read_double('unknown size')
        #   stream.read_double('unknown size')

        for l in self.levels:
            l.read_enabled(stream)
        for l in self.levels:
            l.read_locked(stream)
Exemple #12
0
    def read(self, stream: Stream, version):
        self.ramp = stream.read_object('Color ramp')
        _ = stream.read_object('unused color')

        # either an entire LineSymbol or just a LineSymbolLayer
        outline = stream.read_object('outline')
        if outline is not None:
            if issubclass(outline.__class__, SymbolLayer):
                self.outline_layer = outline
            else:
                self.outline_symbol = outline

        self.percent = stream.read_double('percent')
        self.intervals = stream.read_uint('intervals')
        self.angle = stream.read_double('angle')

        self.type = stream.read_uint('Gradient type')
        stream.read_0d_terminator()
Exemple #13
0
    def processAlgorithm(self, parameters, context, feedback):  # pylint: disable=missing-docstring,too-many-locals,too-many-statements
        input_file = self.parameterAsString(parameters, self.INPUT, context)
        output_file = self.parameterAsFileOutput(parameters, self.OUTPUT,
                                                 context)

        mdbtools_folder = ProcessingConfig.getSetting('MDB_PATH')

        results = {}
        colors = []

        _, file_name = os.path.split(input_file)
        file_name, _ = os.path.splitext(file_name)

        feedback.pushInfo('Importing colors from {}'.format(input_file))

        raw_colors = Extractor.extract_styles(input_file,
                                              Extractor.COLORS,
                                              mdbtools_path=mdbtools_folder)
        feedback.pushInfo('Found {} colors'.format(len(raw_colors)))

        unreadable = 0
        for index, raw_color in enumerate(raw_colors):
            feedback.setProgress(index / len(raw_colors) * 100)
            if feedback.isCanceled():
                break

            name = raw_color[Extractor.NAME]
            feedback.pushInfo('{}/{}: {}'.format(index + 1, len(raw_colors),
                                                 name))

            handle = BytesIO(raw_color[Extractor.BLOB])
            stream = Stream(handle)
            try:
                color = stream.read_object()
            except InvalidColorException:
                feedback.reportError('Error reading color {}'.format(name))
                unreadable += 1
                continue

            qcolor = symbol_color_to_qcolor(color)
            colors.append((name, qcolor))

        results[self.COLOR_COUNT] = len(raw_colors)
        results[self.UNREADABLE_COLOR_COUNT] = unreadable

        with open(output_file, 'wt') as f:
            f.write('GIMP Palette\n')
            f.write('Name: {}\n'.format(file_name))
            f.write('Columns: 4\n')
            f.write('#\n')
            for c in colors:
                f.write('{} {} {} {}\n'.format(c[1].red(), c[1].green(),
                                               c[1].blue(), c[0]))

        results[self.OUTPUT] = output_file
        return results
Exemple #14
0
def read_symbol(_io_stream, debug=False):
    """
    Reads a symbol from the specified file
    """
    stream = Stream(_io_stream, debug)
    try:
        symbol_object = stream.read_object('symbol')
    except InvalidColorException:
        raise UnreadableSymbolException()
    return symbol_object
Exemple #15
0
 def read(self, stream: Stream, version):
     """
     Reads the decoration information
     """
     # next bit is probably number of decorations?
     count = stream.read_uint('count of decorations')
     for i in range(count):
         decoration = stream.read_object('decoration element {}/{}'.format(
             i, count))
         self.decorations.append(decoration)
Exemple #16
0
    def read(self, stream: Stream, version):
        if version == 4:
            self.picture = stream.read_object('picture')
        elif version == 7:
            _ = stream.read_ushort('pic version?')
            _ = stream.read_uint('picture type?')
            self.picture = stream.read_object('picture')
        elif version == 8:
            self.picture = stream.read_picture('picture')

        self.color_background = stream.read_object('color bg')
        self.color_foreground = stream.read_object('color fg')
        self.color_transparent = stream.read_object('color trans')

        # either an entire LineSymbol or just a LineSymbolLayer
        outline = stream.read_object('outline')
        if outline is not None:
            if issubclass(outline.__class__, SymbolLayer):
                self.outline_layer = outline
            else:
                self.outline_symbol = outline

        self.angle = stream.read_double('angle')
        self.scale_x = stream.read_double('scale_x')
        self.scale_y = stream.read_double('scale_y')

        self.offset_x = stream.read_double('offset x')
        self.offset_y = stream.read_double('offset y')
        self.separation_x = stream.read_double('separation x')
        self.separation_y = stream.read_double('separation y')

        stream.read(16)

        stream.read_0d_terminator()

        self.swap_fb_gb = bool(stream.read_uchar('swap fgbg'))

        if version <= 4:
            return

        stream.read(6)
        if version < 8:
            stream.read(4)
Exemple #17
0
    def read(self, stream: Stream, version):
        _ = stream.read_double('unused double')
        _ = stream.read_double('unused double')

        self.line = stream.read_object('pattern line')

        # either an entire LineSymbol or just a LineSymbolLayer
        outline = stream.read_object('outline')
        if outline is not None:
            if issubclass(outline.__class__, SymbolLayer):
                self.outline_layer = outline
            else:
                self.outline_symbol = outline

        self.angle = stream.read_double('angle')
        self.offset = stream.read_double('offset')
        self.separation = stream.read_double('separation')

        stream.read_0d_terminator()
Exemple #18
0
    def _read(self, stream: Stream, version):
        # consume section of unknown purpose
        _ = stream.read_double('unknown size')

        unknown_object = stream.read_object('unknown')
        if unknown_object is not None:
            assert False, unknown_object
        _ = stream.read_double('unknown size')

        self.color = stream.read_object('color')

        self.halo = stream.read_int() == 1
        self.halo_size = stream.read_double('halo size')

        self.halo_symbol = stream.read_object('halo')

        # not sure about this - there's an extra 02 here if a full fill symbol is used for the halo
        if False and isinstance(self.halo_symbol, Symbol):
            check = binascii.hexlify(stream.read(1))
            if check != b'02':
                raise UnreadableSymbolException(
                    'Found unexpected value {} at {}, expected x02'.format(
                        check, hex(stream.tell() - 1)))
            stream.read(1)

        if isinstance(self.halo_symbol, SymbolLayer):
            stream.read(4)

        # useful stuff
        number_layers = stream.read_int('layers')
        for i in range(number_layers):
            layer = stream.read_object('symbol layer {}/{}'.format(
                i + 1, number_layers))
            self.levels.extend([layer])

        for l in self.levels:
            l.read_enabled(stream)
        for l in self.levels:
            l.read_locked(stream)

        _ = stream.read_double('unknown size')
        _ = stream.read_double('unknown size')
Exemple #19
0
 def check_handle(self, file_handle):
     try:
         stream = Stream(file_handle)
         o = stream.read_object()
         if o is not None:
             return PersistentMatch(file_handle.tell() - 1, 1, o)
         else:
             return None
     except:  # nopep8, pylint: disable=bare-except
         pass
     return None
Exemple #20
0
    def read(self, stream: Stream, version):
        if not stream.read_0d_terminator():
            raise UnreadableSymbolException('Could not find 0d terminator at {}'.format(hex(stream.tell() - 8)))

        _ = stream.read_object('unused color')

        number_layers = stream.read_int('layers')
        for i in range(number_layers):
            layer = stream.read_object('symbol layer {}/{}'.format(i + 1, number_layers))
            self.levels.extend([layer])

        # stream.read(4)
        for l in self.levels:
            l.read_enabled(stream)
        for l in self.levels:
            l.read_locked(stream)

        if version >= 2:
            for l in self.levels:
                l.read_tags(stream)
Exemple #21
0
 def check_handle(self, file_handle):
     try:
         start = file_handle.tell()
         stream = Stream(file_handle)
         color = stream.read_object()
         if issubclass(color.__class__, Color):
             return ColorMatch(start, file_handle.tell() - start, color.color_model, color)
         else:
             return None
     except:  # nopep8, pylint: disable=bare-except
         pass
     return None
Exemple #22
0
    def read(self, stream: Stream, version):
        self.color = stream.read_object('color')
        self.size = stream.read_double('size')

        type_code = stream.read_int()
        type_dict = {
            0: 'circle',
            1: 'square',
            2: 'cross',
            3: 'x',
            4: 'diamond'
        }

        if type_code not in type_dict:
            raise UnreadableSymbolException(
                'Unknown marker type at {}, got {}'.format(
                    hex(stream.tell() - 4), type_code))
        stream.log('found a {}'.format(type_dict[type_code]), 4)
        self.type = type_dict[type_code]

        # look for 0d terminator
        if not binascii.hexlify(stream.read(8)) == b'0d00000000000000':
            raise UnreadableSymbolException()

        stream.read_double('unknown')

        self.x_offset = stream.read_double('x offset')
        self.y_offset = stream.read_double('y offset')

        has_outline = stream.read_uchar()
        if has_outline == 1:
            self.outline_enabled = True
        self.outline_width = stream.read_double('outline width')
        self.outline_color = stream.read_object('outline color')

        check = binascii.hexlify(stream.read(2))
        if check != b'ffff':
            raise UnreadableSymbolException(
                'Expected ffff at {}, got {}'.format(check,
                                                     hex(stream.tell() - 2)))
Exemple #23
0
    def read(self, stream: Stream, version):
        if version in (4, 5):
            self.picture = stream.read_object('picture')
        elif version == 8:
            _ = stream.read_ushort('pic version?')
            _ = stream.read_uint('picture type?')
            self.picture = stream.read_object('picture')
        elif version == 9:
            self.picture = stream.read_picture('picture')

        if version <= 8:
            _ = stream.read_object()

        self.color_foreground = stream.read_object('color 1')
        self.color_background = stream.read_object('color 2')

        if version >= 9:
            self.color_transparent = stream.read_object('color 3')

        self.angle = stream.read_double('angle')
        self.size = stream.read_double('size')
        self.x_offset = stream.read_double('x offset')
        self.y_offset = stream.read_double('y offset')

        stream.read_double('unknown')
        stream.read_double('unknown')

        stream.read_0d_terminator()
        self.swap_fb_gb = bool(stream.read_uchar('swap fgbg'))

        check = binascii.hexlify(stream.read(2))
        if check != b'ffff':
            raise UnreadableSymbolException('Expected ffff at {}, got {}'.format(check, hex(stream.tell() - 2)))

        if version < 6:
            return

        stream.read(6)
        if version <= 8:
            stream.read(4)
Exemple #24
0
    def read(self, stream: Stream, version):
        self.random = bool(stream.read_int('random'))
        self.offset_x = stream.read_double('offset x')
        self.offset_y = stream.read_double('offset y')
        self.separation_x = stream.read_double('separation x')
        self.separation_y = stream.read_double('separation y')
        _ = stream.read_double('unused double')
        _ = stream.read_double('unused double')

        self.marker = stream.read_object('fill marker')

        # either an entire LineSymbol or just a LineSymbolLayer
        outline = stream.read_object('outline')
        if outline is not None:
            if issubclass(outline.__class__, SymbolLayer):
                self.outline_layer = outline
            else:
                self.outline_symbol = outline

        stream.read_0d_terminator()

        _ = stream.read_double('unused double')
Exemple #25
0
    def read(self, stream: Stream, version):
        self.cap = self.read_cap(stream)
        stream.log('read cap of {}'.format(self.cap), 1)

        self.offset = stream.read_double('offset')
        self.pattern_marker = stream.read_object('pattern marker')
        self.template = stream.read_object('template')
        self.decoration = stream.read_object('decoration')

        stream.read_0d_terminator()

        _ = stream.read_double('unknown double')
        _ = stream.read_int('unknown int')
        _ = stream.read_uchar('unknown char')

        self.join = self.read_join(stream)
        unknown = binascii.hexlify(stream.read(3))
        if unknown != b'000000':
            raise UnreadableSymbolException(
                'Differing unknown string {}'.format(unknown))

        _ = stream.read_double('unknown double')
Exemple #26
0
    def read(self, stream: Stream, version):
        self.color = stream.read_object('color')

        self.size = stream.read_double('size')
        self.width = stream.read_double('width')
        self.angle = stream.read_double('angle')

        # 12 bytes unknown purpose
        stream.log('skipping 12 unknown bytes')

        _ = stream.read_uint('unknown')
        stream.read_0d_terminator()

        self.x_offset = stream.read_double('x offset')
        self.y_offset = stream.read_double('y offset')

        check = binascii.hexlify(stream.read(2))
        if check != b'ffff':
            raise UnreadableSymbolException('Expected ffff at {}, got {}'.format(check, hex(stream.tell() - 2)))
Exemple #27
0
 def read(self, stream: Stream, version):
     self.color = stream.read_object('color')
     stream.read_0d_terminator()
Exemple #28
0
    def processAlgorithm(self, parameters, context, feedback):  # pylint: disable=missing-docstring,too-many-locals,too-many-statements
        input_file = self.parameterAsString(parameters, self.INPUT, context)
        output_file = self.parameterAsFileOutput(parameters, self.OUTPUT,
                                                 context)

        mdbtools_folder = ProcessingConfig.getSetting('MDB_PATH')

        style = QgsStyle()

        results = {}

        symbol_names = set()

        def make_name_unique(name):
            """
            Ensures that the symbol name is unique (in a case insensitive way)
            """
            counter = 0
            candidate = name
            while candidate.lower() in symbol_names:
                # make name unique
                if counter == 0:
                    candidate += '_1'
                else:
                    candidate = candidate[:candidate.rfind('_') +
                                          1] + str(counter)
                counter += 1
            symbol_names.add(candidate.lower())
            return candidate

        for type_index, symbol_type in enumerate(
            (Extractor.FILL_SYMBOLS, Extractor.LINE_SYMBOLS,
             Extractor.MARKER_SYMBOLS)):
            feedback.pushInfo('Importing {} from {}'.format(
                symbol_type, input_file))

            raw_symbols = Extractor.extract_styles(
                input_file, symbol_type, mdbtools_path=mdbtools_folder)
            feedback.pushInfo('Found {} symbols of type "{}"\n\n'.format(
                len(raw_symbols), symbol_type))

            if feedback.isCanceled():
                break

            unreadable = 0
            for index, raw_symbol in enumerate(raw_symbols):
                feedback.setProgress(index / len(raw_symbols) * 33.3 +
                                     33.3 * type_index)
                if feedback.isCanceled():
                    break
                name = raw_symbol[Extractor.NAME]
                feedback.pushInfo('{}/{}: {}'.format(index + 1,
                                                     len(raw_symbols), name))

                unique_name = make_name_unique(name)
                if name != unique_name:
                    feedback.pushInfo(
                        'Corrected to unique name of {}'.format(unique_name))

                handle = BytesIO(raw_symbol[Extractor.BLOB])
                stream = Stream(handle)
                try:
                    symbol = stream.read_object()
                except UnreadableSymbolException as e:
                    feedback.reportError('Error reading symbol {}: {}'.format(
                        name, e))
                    unreadable += 1
                    continue
                except NotImplementedException as e:
                    feedback.reportError(
                        'Parsing {} is not supported: {}'.format(name, e))
                    unreadable += 1
                    continue
                except UnsupportedVersionException as e:
                    feedback.reportError('Cannot read {} version: {}'.format(
                        name, e))
                    unreadable += 1
                    continue

                try:
                    qgis_symbol = Symbol_to_QgsSymbol(symbol)
                except NotImplementedException as e:
                    feedback.reportError(str(e))
                    unreadable += 1
                    continue

                style.addSymbol(unique_name, qgis_symbol)

            if symbol_type == Extractor.FILL_SYMBOLS:
                results[self.FILL_SYMBOL_COUNT] = len(raw_symbols)
                results[self.UNREADABLE_FILL_SYMBOLS] = unreadable
            elif symbol_type == Extractor.LINE_SYMBOLS:
                results[self.LINE_SYMBOL_COUNT] = len(raw_symbols)
                results[self.UNREADABLE_LINE_SYMBOLS] = unreadable
            elif symbol_type == Extractor.MARKER_SYMBOLS:
                results[self.MARKER_SYMBOL_COUNT] = len(raw_symbols)
                results[self.UNREADABLE_MARKER_SYMBOLS] = unreadable

        style.exportXml(output_file)
        results[self.OUTPUT] = output_file
        return results
Exemple #29
0
    def processAlgorithm(self,  # pylint:disable=missing-docstring,too-many-locals,too-many-statements,too-many-branches
                         parameters,
                         context,
                         feedback):
        input_file = self.parameterAsString(parameters, self.INPUT, context)
        output_file = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
        embed_pictures = self.parameterAsBool(parameters, self.EMBED_PICTURES, context)
        convert_fonts = self.parameterAsBool(parameters, self.CONVERT_FONTS, context)
        parameterize = self.parameterAsBool(parameters, self.PARAMETERIZE, context)
        units = self.parameterAsEnum(parameters, self.UNITS, context)
        force_svg = self.parameterAsBool(parameters, self.FORCE_SVG, context)
        relative_paths = self.parameterAsBool(parameters, self.RELATIVE_PATHS, context)

        picture_folder = self.parameterAsString(parameters, self.PICTURE_FOLDER, context)
        if not picture_folder:
            picture_folder, _ = os.path.split(output_file)

        mdbtools_folder = ProcessingConfig.getSetting('MDB_PATH')

        fields = QgsFields()
        fields.append(QgsField('name', QVariant.String, '', 60))
        fields.append(QgsField('warning', QVariant.String, '', 250))

        sink, dest = self.parameterAsSink(parameters, self.REPORT, context, fields)

        style = QgsStyle()
        style.createMemoryDatabase()

        results = {}

        symbol_names = set()

        def make_name_unique(name):
            """
            Ensures that the symbol name is unique (in a case insensitive way)
            """
            counter = 0
            candidate = name
            while candidate.lower() in symbol_names:
                # make name unique
                if counter == 0:
                    candidate += '_1'
                else:
                    candidate = candidate[:candidate.rfind('_') + 1] + str(counter)
                counter += 1
            symbol_names.add(candidate.lower())
            return candidate

        for type_index, symbol_type in enumerate(
                (Extractor.FILL_SYMBOLS, Extractor.LINE_SYMBOLS, Extractor.MARKER_SYMBOLS, Extractor.COLOR_RAMPS)):
            feedback.pushInfo('Importing {} from {}'.format(symbol_type, input_file))

            raw_symbols = Extractor.extract_styles(input_file, symbol_type, mdbtools_path=mdbtools_folder)
            feedback.pushInfo('Found {} symbols of type "{}"\n\n'.format(len(raw_symbols), symbol_type))

            if feedback.isCanceled():
                break

            unreadable = 0
            for index, raw_symbol in enumerate(raw_symbols):
                feedback.setProgress(index / len(raw_symbols) * 33.3 + 33.3 * type_index)
                if feedback.isCanceled():
                    break
                name = raw_symbol[Extractor.NAME]
                tags = raw_symbol[Extractor.TAGS].split(';')
                feedback.pushInfo('{}/{}: {}'.format(index + 1, len(raw_symbols), name))

                unique_name = make_name_unique(name)
                if name != unique_name:
                    feedback.pushInfo('Corrected to unique name of {}'.format(unique_name))

                handle = BytesIO(raw_symbol[Extractor.BLOB])
                stream = Stream(handle)

                f = QgsFeature()
                try:
                    symbol = stream.read_object()
                except UnreadableSymbolException as e:
                    feedback.reportError('Error reading symbol {}: {}'.format(name, e))
                    unreadable += 1
                    if sink:
                        f.setAttributes([name, 'Error reading symbol: {}'.format(e)])
                        sink.addFeature(f)
                    continue
                except NotImplementedException as e:
                    feedback.reportError('Parsing {} is not supported: {}'.format(name, e))
                    unreadable += 1
                    if sink:
                        f.setAttributes([name, 'Parsing not supported: {}'.format(e)])
                        sink.addFeature(f)
                    continue
                except UnsupportedVersionException as e:
                    feedback.reportError('Cannot read {} version: {}'.format(name, e))
                    unreadable += 1
                    if sink:
                        f.setAttributes([name, 'Version not supported: {}'.format(e)])
                        sink.addFeature(f)
                    continue
                except UnknownGuidException as e:
                    feedback.reportError(str(e))
                    unreadable += 1
                    if sink:
                        f.setAttributes([name, 'Unknown object: {}'.format(e)])
                        sink.addFeature(f)
                    continue
                except UnreadablePictureException as e:
                    feedback.reportError(str(e))
                    unreadable += 1
                    if sink:
                        f.setAttributes([name, 'Unreadable picture: {}'.format(e)])
                        sink.addFeature(f)
                    continue

                self.check_for_unsupported_property(name, symbol, feedback, sink)

                context = Context()
                context.symbol_name = unique_name
                context.picture_folder = picture_folder
                context.embed_pictures = embed_pictures
                context.convert_fonts = convert_fonts
                context.parameterise_svg = parameterize
                context.force_svg_instead_of_raster = force_svg
                context.relative_paths = relative_paths
                context.style_folder, _ = os.path.split(output_file)
                context.units = QgsUnitTypes.RenderPoints if units == 0 else QgsUnitTypes.RenderMillimeters

                try:
                    qgis_symbol = Symbol_to_QgsSymbol(symbol, context)
                except NotImplementedException as e:
                    feedback.reportError(str(e))
                    unreadable += 1
                    if sink:
                        f.setAttributes([name, str(e)])
                        sink.addFeature(f)
                    continue

                if isinstance(qgis_symbol, QgsSymbol):
                    self.check_for_missing_fonts(qgis_symbol, feedback)
                    style.addSymbol(unique_name, qgis_symbol, True)
                elif isinstance(qgis_symbol, QgsColorRamp):
                    style.addColorRamp(unique_name, qgis_symbol, True)

                if tags:
                    if isinstance(qgis_symbol, QgsSymbol):
                        assert style.tagSymbol(QgsStyle.SymbolEntity, unique_name, tags)
                    elif isinstance(qgis_symbol, QgsColorRamp):
                        assert style.tagSymbol(QgsStyle.ColorrampEntity, unique_name, tags)

            if symbol_type == Extractor.FILL_SYMBOLS:
                results[self.FILL_SYMBOL_COUNT] = len(raw_symbols)
                results[self.UNREADABLE_FILL_SYMBOLS] = unreadable
            elif symbol_type == Extractor.LINE_SYMBOLS:
                results[self.LINE_SYMBOL_COUNT] = len(raw_symbols)
                results[self.UNREADABLE_LINE_SYMBOLS] = unreadable
            elif symbol_type == Extractor.MARKER_SYMBOLS:
                results[self.MARKER_SYMBOL_COUNT] = len(raw_symbols)
                results[self.UNREADABLE_MARKER_SYMBOLS] = unreadable
            elif symbol_type == Extractor.COLOR_RAMPS:
                results[self.COLOR_RAMP_COUNT] = len(raw_symbols)
                results[self.UNREADABLE_COLOR_RAMPS] = unreadable

        style.exportXml(output_file)
        results[self.OUTPUT] = output_file
        results[self.REPORT] = dest
        return results