Exemple #1
0
    def _get_transformed(self, query, format):
        dst_srs = query.srs
        src_srs = self._best_supported_srs(dst_srs)
        dst_bbox = query.bbox
        src_bbox = dst_srs.transform_bbox_to(src_srs, dst_bbox)
        
        src_width, src_height = src_bbox[2]-src_bbox[0], src_bbox[3]-src_bbox[1]
        ratio = src_width/src_height
        dst_size = query.size
        xres, yres = src_width/dst_size[0], src_height/dst_size[1]
        if xres < yres:
            src_size = dst_size[0], int(dst_size[0]/ratio + 0.5)
        else:
            src_size = int(dst_size[1]*ratio +0.5), dst_size[1]
        
        src_query = MapQuery(src_bbox, src_size, src_srs, format)

        if self.coverage and not self.coverage.contains(src_bbox, src_srs):
            img = self._get_sub_query(src_query, format)
        else:
            resp = self.client.retrieve(src_query, format)
            img = ImageSource(resp, size=src_size, image_opts=self.image_opts)
        
        img = ImageTransformer(src_srs, dst_srs).transform(img, src_bbox, 
            query.size, dst_bbox, self.image_opts)
        
        img.format = format
        return img
Exemple #2
0
 def test_output_formats_png24(self):
     img = Image.new('RGBA', (100, 100))
     image_opts = PNG_FORMAT.copy()
     image_opts.colors = 0 # TODO image_opts
     ir = ImageSource(img, image_opts=image_opts)
     img = Image.open(ir.as_buffer())
     eq_(img.mode, 'RGBA')
     assert img.getpixel((0, 0)) == (0, 0, 0, 0)
Exemple #3
0
    def test_save_with_unsupported_transparency(self):
        # check if encoding of non-RGB image with tuple as transparency
        # works. workaround for Pillow #2633
        img = Image.new('P', (100, 100))
        img.info['transparency'] = (0, 0, 0)
        image_opts = PNG_FORMAT.copy()

        ir = ImageSource(img, image_opts=image_opts)
        img = Image.open(ir.as_buffer())
        eq_(img.mode, 'P')
Exemple #4
0
 def test_from_non_seekable_file(self):
     with open(self.tmp_filename, 'rb') as tmp_file:
         data = tmp_file.read()
         
     class FileLikeDummy(object):
         # "file" without seek, like urlopen response
         def read(self):
             return data
     
     ir = ImageSource(FileLikeDummy(), 'png')
     assert ir.as_buffer(seekable=True).read() == data
     assert ir.as_image().size == (100, 100)
     assert ir.as_buffer().read() == data
Exemple #5
0
class TestTransform(object):
    def setup(self):
        self.src_img = ImageSource(create_debug_img((200, 200), transparent=False))
        self.src_srs = SRS(31467)
        self.dst_size = (100, 150)
        self.dst_srs = SRS(4326)
        self.dst_bbox = (0.2, 45.1, 8.3, 53.2)
        self.src_bbox = self.dst_srs.transform_bbox_to(self.src_srs, self.dst_bbox)
    def test_transform(self, mesh_div=4):
        transformer = ImageTransformer(self.src_srs, self.dst_srs, mesh_div=mesh_div)
        result = transformer.transform(self.src_img, self.src_bbox, self.dst_size, self.dst_bbox,
            image_opts=ImageOptions(resampling='nearest'))
        assert isinstance(result, ImageSource)
        assert result.as_image() != self.src_img.as_image()
        assert result.size == (100, 150)

    def _test_compare_mesh_div(self):
        """
        Create transformations with different div values.
        """
        for div in [1, 2, 4, 6, 8, 12, 16]:
            transformer = ImageTransformer(self.src_srs, self.dst_srs, mesh_div=div)
            result = transformer.transform(self.src_img, self.src_bbox,
                                           self.dst_size, self.dst_bbox)
            result.as_image().save('/tmp/transform-%d.png' % (div,))
Exemple #6
0
 def setup(self):
     self.src_img = ImageSource(create_debug_img((200, 200), transparent=False))
     self.src_srs = SRS(31467)
     self.dst_size = (100, 150)
     self.dst_srs = SRS(4326)
     self.dst_bbox = (0.2, 45.1, 8.3, 53.2)
     self.src_bbox = self.dst_srs.transform_bbox_to(self.src_srs, self.dst_bbox)
Exemple #7
0
 def test_converted_output(self):
     ir = ImageSource(self.tmp_filename, (100, 100), PNG_FORMAT)
     assert is_png(ir.as_buffer())
     assert is_jpeg(ir.as_buffer(JPEG_FORMAT))
     assert is_jpeg(ir.as_buffer())
     assert is_tiff(ir.as_buffer(TIFF_FORMAT))
     assert is_tiff(ir.as_buffer())
Exemple #8
0
    def test_paletted_merge(self):
        # generate RGBA images with a transparent rectangle in the lower right
        img1 = ImageSource(Image.new("RGBA", (50, 50), (0, 255, 0, 255))).as_image()
        draw = ImageDraw.Draw(img1)
        draw.rectangle((25, 25, 49, 49), fill=(0, 0, 0, 0))
        paletted_img = quantize(img1, alpha=True)
        assert img_has_transparency(paletted_img)
        assert paletted_img.mode == "P"

        rgba_img = Image.new("RGBA", (50, 50), (255, 0, 0, 255))
        draw = ImageDraw.Draw(rgba_img)
        draw.rectangle((25, 25, 49, 49), fill=(0, 0, 0, 0))

        img1 = ImageSource(paletted_img)
        img2 = ImageSource(rgba_img)

        # generate base image and merge the others above
        img3 = ImageSource(Image.new("RGBA", (50, 50), (0, 0, 255, 255)))
        result = merge_images([img3, img1, img2], ImageOptions(transparent=True))
        img = result.as_image()

        assert img.mode == "RGBA"
        assert img.getpixel((49, 49)) == (0, 0, 255, 255)
        assert img.getpixel((0, 0)) == (255, 0, 0, 255)
Exemple #9
0
 def test_invalid_tile(self):
     self.cleanup_tiles = [
         create_tmp_image_file((100, 100)) for _ in range(9)
     ]
     self.tiles = [ImageSource(tile) for tile in self.cleanup_tiles]
     invalid_tile = self.tiles[0].source
     with open(invalid_tile, "wb") as tmp:
         tmp.write(b"invalid")
     m = TileMerger(tile_grid=(3, 3), tile_size=(100, 100))
     img_opts = ImageOptions(bgcolor=(200, 0, 50))
     result = m.merge(self.tiles, img_opts)
     img = result.as_image()
     assert img.size == (300, 300)
     assert img.getcolors() == [(10000, (200, 0, 50)), (80000, (0, 0, 0))]
     assert not os.path.isfile(invalid_tile)
Exemple #10
0
 def test_args(self):
     def callback(img_src, service, layers, environ, query_extent, **kw):
         assert isinstance(img_src, ImageSource)
         eq_('wms.map', service)
         assert isinstance(layers, list)
         assert isinstance(environ, dict)
         assert len(query_extent) == 2
         assert len(query_extent[1]) == 4
         return img_src
     img_src1 = ImageSource(Image.new('RGBA', (100, 100)))
     env = make_wsgi_env('', extra_environ={'mapproxy.decorate_img': callback})
     img_src2 = self.tile_server.decorate_img(
         img_src1, 'wms.map', ['layer1'],
         env, self.query_extent
     )
Exemple #11
0
 def load_tile(self, tile, with_metadata=False):
     # bulk loading with load_tiles is not implemented, because
     # CouchDB's /all_docs? does not include attachments
     
     if tile.source or tile.coord is None:
         return True
     url = self.document_url(tile.coord) + '?attachments=true'
     resp = requests.get(url, headers={'Accept': 'application/json'})
     if resp.status_code == 200:
         doc = json.loads(resp.content)
         tile_data = StringIO(doc['_attachments']['tile']['data'].decode('base64'))
         tile.source = ImageSource(tile_data)
         tile.timestamp = doc.get(self.md_template.timestamp_key)
         return True
     return False
Exemple #12
0
    def load_tiles(self, tiles, with_metadata=False, dimensions=None):
        #associate the right tiles with the cursor
        tile_dict = {}
        coords = []
        for tile in tiles:
            if tile.source or tile.coord is None:
                continue
            x, y, level = tile.coord
            coords.append(x)
            coords.append(y)
            coords.append(level)
            tile_dict[(x, y)] = tile

        if not tile_dict:
            # all tiles loaded or coords are None
            return True

        if self.supports_timestamp:
            stmt_base = "SELECT tile_column, tile_row, tile_data, last_modified FROM tiles WHERE "
        else:
            stmt_base = "SELECT tile_column, tile_row, tile_data FROM tiles WHERE "

        loaded_tiles = 0

        # SQLite is limited to 1000 args -> split into multiple requests if more arguments are needed
        while coords:
            cur_coords = coords[:999]

            stmt = stmt_base + ' OR '.join(
                ['(tile_column = ? AND tile_row = ? AND zoom_level = ?)'] *
                (len(cur_coords) // 3))

            cursor = self.db.cursor()
            cursor.execute(stmt, cur_coords)

            for row in cursor:
                loaded_tiles += 1
                tile = tile_dict[(row[0], row[1])]
                data = row[2]
                tile.size = len(data)
                tile.source = ImageSource(BytesIO(data))
                if self.supports_timestamp:
                    tile.timestamp = sqlite_datetime_to_timestamp(row[3])
            cursor.close()

            coords = coords[999:]

        return loaded_tiles == len(tile_dict)
Exemple #13
0
    def load_tile(self, tile, with_metadata=False, dimensions=None):
        if tile.timestamp is None:
            tile.timestamp = 0
        if tile.source or tile.coord is None:
            return True

        res = self._get_object(tile.coord)
        if res.exists:
            tile_data = BytesIO(res.encoded_data)
            tile.source = ImageSource(tile_data)
            if with_metadata:
                tile.timestamp = self._get_timestamp(res)
                tile.size = len(res.encoded_data)
            return True

        return False
Exemple #14
0
    def load_tile(self, tile, with_metadata=False):
        if tile.source or tile.coord is None:
            return True

        cur = self.db.cursor()
        cur.execute("""SELECT tile_data FROM [{0}]
                WHERE tile_column = ? AND
                      tile_row = ? AND
                      zoom_level = ?""".format(self.table_name), tile.coord)

        content = cur.fetchone()
        if content:
            tile.source = ImageSource(BytesIO(content[0]))
            return True
        else:
            return False
Exemple #15
0
    def test_background_larger_crop_with_transparent(self):
        img = ImageSource(Image.new('RGBA', (356, 266), (130, 140, 120, 255)))
        img_opts = ImageOptions('RGBA', transparent=True)
        splitter = TileSplitter(img, img_opts)

        tile = splitter.get_tile((0, 0), (256, 256))

        eq_(tile.size, (256, 256))
        colors = tile.as_image().getcolors()
        eq_(colors, [(256*256, (130, 140, 120, 255))])

        tile = splitter.get_tile((256, 256), (256, 256))

        eq_(tile.size, (256, 256))
        colors = tile.as_image().getcolors()
        eq_(sorted(colors), [(10*100, (130, 140, 120, 255)), (256*256-10*100, (255, 255, 255, 0))])
Exemple #16
0
    def load_tile(self, tile, with_metadata=True):
        if not tile.is_missing():
            return True

        key = self.tile_key(tile)
        log.debug('AzureBlob:load_tile, key: %s' % key)

        try:
            r  = self.conn.download_blob(key)
            tile.timestamp = calendar.timegm(r.properties.last_modified.timetuple())
            tile.size = r.properties.size
            tile.source = ImageSource(BytesIO(r.readall()))
        except Exception as e:
            return False

        return True
    def test_defragmentation_empty_bundle(self):
        cache = self.cache_class(self.cache_dir)

        t = Tile((5000, 1000, 12),
                 ImageSource(BytesIO(b'a' * 60 * 1024),
                             image_opts=ImageOptions(format='image/png')))
        cache.store_tile(t)
        cache.remove_tile(t)

        fname = os.path.join(self.cache_dir, 'L12', 'R0380C1380.bundle')
        assert os.path.exists(fname)

        logger = mockProgressLog()
        defrag_compact_cache(cache, min_bytes=50000, log_progress=logger)

        assert not os.path.exists(fname)
Exemple #18
0
    def load_tile(self, tile, with_metadata=False):
        """
        Fills the `Tile.source` of the `tile` if it is cached.
        If it is not cached or if the ``.coord`` is ``None``, nothing happens.
        """
        if not tile.is_missing():
            return True

        location = self.tile_location(tile)

        if os.path.exists(location):
            if with_metadata:
                self.load_tile_metadata(tile)
            tile.source = ImageSource(location)
            return True
        return False
Exemple #19
0
    def test_scaled_tiles(self, name, file_cache, tile_locker, rescale_tiles, tiles, store, expected_load, output):
        res = [
            1.40625,               # 0
            0.703125,              # 1
            0.3515625,             # 2
            0.17578125,            # 3
            0.087890625,           # 4
            0.0439453125,          # 5
            0.02197265625,         # 6
            0.010986328125,        # 7
            0.007,                 # 8 additional resolution to test unregular grids
            0.0054931640625,       # 9
            0.00274658203125,      # 10
        ]
        grid = TileGrid(SRS(4326), origin='sw', bbox=[-180, -90, 180, 90], res=res)
        image_opts = ImageOptions(format='image/png', resampling='nearest')
        tm = TileManager(
            grid, file_cache, [], 'png',
            locker=tile_locker,
            image_opts=image_opts,
            rescale_tiles=rescale_tiles,
        )

        if store:
            colors = set()
            if output == "partial":
                colors.add((255, 255, 255))
            for i, t in enumerate(store):
                color = (150+i*35, 5+i*35, 5+i*35)
                colors.add(color)
                tile = Tile(t, ImageSource(create_tmp_image_buf((256, 256), color=color)))
                file_cache.store_tile(tile)

            loaded_tiles = tm.load_tile_coords(tiles)
            assert not is_blank(loaded_tiles)
            assert len(loaded_tiles) == len(tiles)
            got_colors = set()
            for t in loaded_tiles:
                got_colors.update([c for _, c in t.source.as_image().getcolors()])
            assert got_colors == colors
        else:
            loaded_tiles = tm.load_tile_coords(tiles)
            assert is_blank(loaded_tiles) == (output == "blank")
            assert len(loaded_tiles.tiles) == len(tiles)

        assert file_cache.stored_tiles == set(store)
        assert file_cache.loaded_tiles == counting_set(expected_load)
    def test_filter_with_alpha(self):
        img = Image.new('RGBA', (200, 200), (10, 15, 20, 0))
        orig_source = ImageSource(img)
        self.tile.source = orig_source
        filtered_tile = self.filter(self.tile)

        assert self.tile is filtered_tile
        assert orig_source != filtered_tile.source

        pil_img = filtered_tile.source.as_image()
        eq_(pil_img.getpixel((0, 0)), (10, 15, 20, 0))

        colors = pil_img.getcolors()
        colors.sort()
        # most but not all parts are bg color
        assert 39950 > colors[-1][0] > 39000
        eq_(colors[-1][1], (10, 15, 20, 0))
Exemple #21
0
    def load_tile(self, tile, with_metadata=False):
        if tile.source or tile.coord is None:
            return True

        idx = BundleIndex(self.base_filename + BUNDLEX_EXT)
        x, y = self._rel_tile_coord(tile.coord)
        offset = idx.tile_offset(x, y)
        if offset == 0:
            return False

        bundle = BundleData(self.base_filename + BUNDLE_EXT, self.offset)
        data = bundle.read_tile(offset)
        if not data:
            return False
        tile.source = ImageSource(BytesIO(data))

        return True
Exemple #22
0
    def test_wkt_mask_partial_image_transparent(self):
        img = ImageSource(
            Image.new("RGB", (100, 100), color=(100, 0, 200)),
            image_opts=ImageOptions(transparent=True),
        )

        # polygon with hole
        geom = "POLYGON((2 2, 2 8, 8 8, 8 2, 2 2), (4 4, 4 6, 6 6, 6 4, 4 4))"

        result = mask_image_source_from_coverage(
            img, [0, 0, 10, 10], SRS(4326), coverage(geom)
        )
        # 60*60 - 20*20 = 3200
        assert_img_colors_eq(
            result.as_image().getcolors(),
            [(10000 - 3200, (255, 255, 255, 0)), (3200, (100, 0, 200, 255))],
        )
Exemple #23
0
    def test_shapely_mask_with_transform_partial_image_transparent(self):
        img = ImageSource(
            Image.new("RGB", (100, 100), color=(100, 0, 200)),
            image_opts=ImageOptions(transparent=True),
        )

        p = Polygon(
            [(0, 0), (222000, 0), (222000, 222000), (0, 222000)]
        )  # ~ 2x2 degres

        result = mask_image_source_from_coverage(
            img, [0, 0, 10, 10], SRS(4326), coverage(p, "EPSG:3857")
        )
        # 20*20 = 400
        assert_img_colors_eq(
            result.as_image().getcolors(),
            [(10000 - 400, (255, 255, 255, 0)), (400, (100, 0, 200, 255))],
        )
Exemple #24
0
    def load_tile(self, tile, with_metadata=True):
        if not tile.is_missing():
            return True

        key = self.tile_key(tile)
        log.debug('S3:load_tile, key: %s' % key)

        try:
            r  = self.conn().get_object(Bucket=self.bucket_name, Key=key)
            self._set_metadata(r, tile)
            tile.source = ImageSource(r['Body'])
        except botocore.exceptions.ClientError as e:
            error = e.response.get('Errors', e.response)['Error'] # moto get_object can return Error wrapped in Errors...
            if error['Code'] in ('404', 'NoSuchKey'):
                return False
            raise

        return True
Exemple #25
0
 def _get_map(self, query):
     format = self.image_opts.format
     if not format:
         format = query.format
     if self.supported_formats and format not in self.supported_formats:
         format = self.supported_formats[0]
     if self.supported_srs:
         if query.srs not in self.supported_srs:
             return self._get_transformed(query, format)
         # some srs are equal but not the same (e.g. 900913/3857)
         # use only supported srs so we use the right srs code.
         idx = self.supported_srs.index(query.srs)
         if self.supported_srs[idx] is not query.srs:
             query.srs = self.supported_srs[idx]
     if self.extent and not self.extent.contains(MapExtent(query.bbox, query.srs)):
         return self._get_sub_query(query, format)
     resp = self.client.retrieve(query, format)
     return ImageSource(resp, size=query.size, image_opts=self.image_opts)
Exemple #26
0
    def load_tile(self, tile, with_metadata=False, dimensions=None):
        # bulk loading with load_tiles is not implemented, because
        # CouchDB's /all_docs? does not include attachments

        if tile.source or tile.coord is None:
            return True
        url = self.document_url(tile.coord) + '?attachments=true'
        self.init_db()
        resp = self.req_session.get(url,
                                    headers={'Accept': 'application/json'})
        if resp.status_code == 200:
            doc = json.loads(codecs.decode(resp.content, 'utf-8'))
            tile_data = BytesIO(
                base64.b64decode(doc['_attachments']['tile']['data']))
            tile.source = ImageSource(tile_data)
            tile.timestamp = doc.get(self.md_template.timestamp_key)
            return True
        return False
Exemple #27
0
    def load_tiles(self, tiles, with_metadata=False):
        #associate the right tiles with the cursor
        tile_dict = {}
        coords = []
        for tile in tiles:
            if tile.source or tile.coord is None:
                continue
            x, y, level = tile.coord
            coords.append(x)
            coords.append(y)
            coords.append(level)
            tile_dict[(x, y)] = tile

        if not tile_dict:
            # all tiles loaded or coords are None
            return True

        if len(coords) > 1000:
            # SQLite is limited to 1000 args
            raise CacheBackendError(
                'cannot query SQLite for more than 333 tiles')

        if self.supports_timestamp:
            stmt = "SELECT tile_column, tile_row, tile_data, last_modified FROM tiles WHERE "
        else:
            stmt = "SELECT tile_column, tile_row, tile_data FROM tiles WHERE "
        stmt += ' OR '.join(
            ['(tile_column = ? AND tile_row = ? AND zoom_level = ?)'] *
            (len(coords) // 3))

        cursor = self.db.cursor()
        cursor.execute(stmt, coords)

        loaded_tiles = 0
        for row in cursor:
            loaded_tiles += 1
            tile = tile_dict[(row[0], row[1])]
            data = row[2]
            tile.size = len(data)
            tile.source = ImageSource(BytesIO(data))
            if self.supports_timestamp:
                tile.timestamp = sqlite_datetime_to_timestamp(row[3])
        cursor.close()
        return loaded_tiles == len(tile_dict)
Exemple #28
0
    def merge(self, ordered_tiles, image_opts):
        """
        Merge all tiles into one image.

        :param ordered_tiles: list of tiles, sorted row-wise (top to bottom)
        :rtype: `ImageSource`
        """
        if self.tile_grid == (1, 1):
            assert len(ordered_tiles) == 1
            if ordered_tiles[0] is not None:
                tile = ordered_tiles.pop()
                return tile
        src_size = self._src_size()

        result = create_image(src_size, image_opts)

        cacheable = True

        for i, source in enumerate(ordered_tiles):
            if source is None:
                continue
            try:
                if not source.cacheable:
                    cacheable = False
                tile = source.as_image()
                pos = self._tile_offset(i)
                tile.draft(image_opts.mode, self.tile_size)
                result.paste(tile, pos)
                source.close_buffers()
            except IOError as e:
                if e.errno is None:  # PIL error
                    log.warning(
                        'unable to load tile %s, removing it (reason was: %s)'
                        % (source, str(e)))
                    if getattr(source, 'filename'):
                        if os.path.exists(source.filename):
                            os.remove(source.filename)
                else:
                    raise
        return ImageSource(result,
                           size=src_size,
                           image_opts=image_opts,
                           cacheable=cacheable)
Exemple #29
0
    def test_background_larger_crop_with_transparent(self):
        img = ImageSource(Image.new("RGBA", (356, 266), (130, 140, 120, 255)))
        img_opts = ImageOptions("RGBA", transparent=True)
        splitter = TileSplitter(img, img_opts)

        tile = splitter.get_tile((0, 0), (256, 256))

        assert tile.size == (256, 256)
        colors = tile.as_image().getcolors()
        assert colors == [(256 * 256, (130, 140, 120, 255))]

        tile = splitter.get_tile((256, 256), (256, 256))

        assert tile.size == (256, 256)
        colors = tile.as_image().getcolors()
        assert sorted(colors) == [
            (10 * 100, (130, 140, 120, 255)),
            (256 * 256 - 10 * 100, (255, 255, 255, 0)),
        ]
Exemple #30
0
def concat_legends(legends, format='png', size=None, bgcolor='#ffffff', transparent=True):
    """
    Merge multiple legends into one
    :param images: list of `ImageSource`, bottom image first
    :param format: the format of the output `ImageSource`
    :param size: size of the merged image, if ``None`` the size
                 will be calculated
    :rtype: `ImageSource`
    """
    if not legends:
        return BlankImageSource(size=(1,1), image_opts=ImageOptions(bgcolor=bgcolor, transparent=transparent))
    if len(legends) == 1:
        return legends[0]

    legends = legends[:]
    legends.reverse()
    if size is None:
        legend_width = 0
        legend_height = 0
        legend_position_y = []
        #iterate through all legends, last to first, calc img size and remember the y-position
        for legend in legends:
            legend_position_y.append(legend_height)
            tmp_img = legend.as_image()
            legend_width = max(legend_width, tmp_img.size[0])
            legend_height += tmp_img.size[1] #images shall not overlap themselfs

        size = [legend_width, legend_height]
    bgcolor = ImageColor.getrgb(bgcolor)

    if transparent:
        img = Image.new('RGBA', size, bgcolor+(0,))
    else:
        img = Image.new('RGB', size, bgcolor)
    for i in range(len(legends)):
        legend_img = legends[i].as_image()
        if legend_img.mode == 'RGBA':
            # paste w transparency mask from layer
            img.paste(legend_img, (0, legend_position_y[i]), legend_img)
        else:
            img.paste(legend_img, (0, legend_position_y[i]))
    return ImageSource(img, image_opts=ImageOptions(format=format))
Exemple #31
0
    def _transform(self, src_img, src_bbox, dst_size, dst_bbox, image_opts):
        """
        Do a 'real' transformation with a transformed mesh (see above).
        """
        src_bbox = self.src_srs.align_bbox(src_bbox)
        dst_bbox = self.dst_srs.align_bbox(dst_bbox)
        src_size = src_img.size
        src_quad = (0, 0, src_size[0], src_size[1])
        dst_quad = (0, 0, dst_size[0], dst_size[1])
        to_src_px = make_lin_transf(src_bbox, src_quad)
        to_dst_w = make_lin_transf(dst_quad, dst_bbox)
        meshes = []

        # more recent versions of Pillow use center coordinates for
        # transformations, we manually need to add half a pixel otherwise
        if transform_uses_center():
            px_offset = 0.0
        else:
            px_offset = 0.5

        def dst_quad_to_src(quad):
            src_quad = []
            for dst_px in [(quad[0], quad[1]), (quad[0], quad[3]),
                           (quad[2], quad[3]), (quad[2], quad[1])]:
                dst_w = to_dst_w(
                    (dst_px[0] + px_offset, dst_px[1] + px_offset))
                src_w = self.dst_srs.transform_to(self.src_srs, dst_w)
                src_px = to_src_px(src_w)
                src_quad.extend(src_px)
            return quad, src_quad

        mesh_div = self.mesh_div
        while mesh_div > 1 and (dst_size[0] / mesh_div < 10
                                or dst_size[1] / mesh_div < 10):
            mesh_div -= 1
        for quad in griddify(dst_quad, mesh_div):
            meshes.append(dst_quad_to_src(quad))

        img = img_for_resampling(src_img.as_image(), image_opts.resampling)
        result = img.transform(dst_size, Image.MESH, meshes,
                               image_filter[image_opts.resampling])
        return ImageSource(result, size=dst_size, image_opts=image_opts)
Exemple #32
0
    def test_from_mixed_merge(self):
        """
        Check merge RGBA bands from image without alpha (mixed)
        """
        merger = BandMerger(mode="RGBA")

        merger.add_ops(dst_band=0, src_img=0, src_band=2)
        merger.add_ops(dst_band=1, src_img=0, src_band=1)
        merger.add_ops(dst_band=2, src_img=0, src_band=0)
        merger.add_ops(dst_band=3, src_img=0, src_band=3)

        img = Image.new("RGB", (10, 10), (0, 100, 200))
        src_img = ImageSource(img)

        img_opts = ImageOptions("RGBA")
        result = merger.merge([src_img], img_opts)

        img = result.as_image()
        assert img.mode == "RGBA"
        assert img.getpixel((0, 0)) == (200, 100, 0, 255)
Exemple #33
0
    def _render_mapfile(self, mapfile, query):
        start_time = time.time()

        m = self.map_obj(mapfile)
        m.resize(query.size[0], query.size[1])
        m.srs = '+init=%s' % str(query.srs.srs_code.lower())
        envelope = mapnik.Box2d(*query.bbox)
        m.zoom_to_box(envelope)
        data = None

        try:
            if self.layers:
                i = 0
                for layer in m.layers[:]:
                    if layer.name != 'Unkown' and layer.name not in self.layers:
                        del m.layers[i]
                    else:
                        i += 1

            img = mapnik.Image(query.size[0], query.size[1])
            if self.scale_factor:
                mapnik.render(m, img, self.scale_factor)
            else:
                mapnik.render(m, img)
            data = img.tostring(str(query.format))
        finally:
            size = None
            if data:
                size = len(data)
            log_request('%s:%s:%s:%s' %
                        (mapfile, query.bbox, query.srs.srs_code, query.size),
                        status='200' if data else '500',
                        size=size,
                        method='API',
                        duration=time.time() - start_time)

        return ImageSource(BytesIO(data),
                           size=query.size,
                           image_opts=ImageOptions(
                               transparent=self.transparent,
                               format=query.format))
Exemple #34
0
    def test_from_p_merge(self):
        """
        Check merge bands from paletted image
        """
        merger = BandMerger(mode="RGB")

        merger.add_ops(dst_band=0, src_img=0, src_band=2)
        merger.add_ops(dst_band=1, src_img=0, src_band=1)
        merger.add_ops(dst_band=2, src_img=0, src_band=0)

        img = Image.new("RGB", (10, 10), (0, 100, 200)).quantize(256)
        assert img.mode == "P"
        # src img is P but we can still access RGB bands
        src_img = ImageSource(img)

        img_opts = ImageOptions("RGB")
        result = merger.merge([src_img], img_opts)

        img = result.as_image()
        assert img.mode == "RGB"
        assert img.getpixel((0, 0)) == (200, 100, 0)
Exemple #35
0
class TestTransform(object):
    def setup(self):
        self.src_img = ImageSource(
            create_debug_img((200, 200), transparent=False))
        self.src_srs = SRS(31467)
        self.dst_size = (100, 150)
        self.dst_srs = SRS(4326)
        self.dst_bbox = (0.2, 45.1, 8.3, 53.2)
        self.src_bbox = self.dst_srs.transform_bbox_to(self.src_srs,
                                                       self.dst_bbox)

    def test_transform(self):
        transformer = ImageTransformer(self.src_srs, self.dst_srs)
        result = transformer.transform(
            self.src_img,
            self.src_bbox,
            self.dst_size,
            self.dst_bbox,
            image_opts=ImageOptions(resampling="nearest"),
        )
        assert isinstance(result, ImageSource)
        assert result.as_image() != self.src_img.as_image()
        assert result.size == (100, 150)

    def _test_compare_max_px_err(self):
        """
        Create transformations with different div values.
        """
        for err in [0.2, 0.5, 1, 2, 4, 6, 8, 12, 16]:
            transformer = ImageTransformer(self.src_srs,
                                           self.dst_srs,
                                           max_px_err=err)
            result = transformer.transform(
                self.src_img,
                self.src_bbox,
                self.dst_size,
                self.dst_bbox,
                image_opts=ImageOptions(resampling="nearest"),
            )
            result.as_image().save("/tmp/transform-%03d.png" % (err * 10, ))
Exemple #36
0
    def load_tiles(self, tiles, with_metadata=False):
        missing = False

        with self.index().readonly() as idx:
            if not idx:
                return False
            with self.data().readonly() as bundle:
                for t in tiles:
                    if t.source or t.coord is None:
                        continue
                    x, y = self._rel_tile_coord(t.coord)
                    offset = idx.tile_offset(x, y)
                    if offset == 0:
                        missing = True
                        continue

                    data = bundle.read_tile(offset)
                    if not data:
                        missing = True
                        continue
                    t.source = ImageSource(BytesIO(data))

        return not missing
Exemple #37
0
    def get_tile(self, crop_coord, tile_size):
        """
        Return the cropped tile.
        :param crop_coord: the upper left pixel coord to start
        :param tile_size: width and height of the new tile
        :rtype: `ImageSource`
        """
        minx, miny = crop_coord
        maxx = minx + tile_size[0]
        maxy = miny + tile_size[1]

        if (minx < 0 or miny < 0 or maxx > self.meta_img.size[0]
                or maxy > self.meta_img.size[1]):

            crop = self.meta_img.crop(
                (max(minx, 0), max(miny, 0), min(maxx, self.meta_img.size[0]),
                 min(maxy, self.meta_img.size[1])))
            result = create_image(tile_size, self.image_opts)
            result.paste(crop, (abs(min(minx, 0)), abs(min(miny, 0))))
            crop = result
        else:
            crop = self.meta_img.crop((minx, miny, maxx, maxy))
        return ImageSource(crop, size=tile_size, image_opts=self.image_opts)
Exemple #38
0
 def test_output_formats_png8(self):
     img = Image.new('RGBA', (100, 100))
     ir = ImageSource(img, image_opts=PNG_FORMAT)
     img = Image.open(ir.as_buffer(ImageOptions(colors=256, transparent=True, format='image/png')))
     assert img.mode == 'P'
     assert img.getpixel((0, 0)) == 255
Exemple #39
0
 def test_from_filename(self):
     ir = ImageSource(self.tmp_filename, PNG_FORMAT)
     assert is_png(ir.as_buffer())
     assert ir.as_image().size == (100, 100)
Exemple #40
0
 def test_output_formats(self):
     img = Image.new('RGB', (100, 100))
     for format in ['png', 'gif', 'tiff', 'jpeg', 'GeoTIFF', 'bmp']:
         ir = ImageSource(img, (100, 100), image_opts=ImageOptions(format=format))
         yield check_format, ir.as_buffer(), format
Exemple #41
0
 def test_from_file(self):
     with open(self.tmp_filename, 'rb') as tmp_file:
         ir = ImageSource(tmp_file, 'png')
         assert ir.as_buffer() == tmp_file
         assert ir.as_image().size == (100, 100)
Exemple #42
0
 def test_from_image(self):
     img = Image.new('RGBA', (100, 100))
     ir = ImageSource(img, (100, 100), PNG_FORMAT)
     assert ir.as_image() == img
     assert is_png(ir.as_buffer())