示例#1
0
 async def new(
         cls,
         text: str,
         *,
         size: conint(  # type:ignore
             strict=True,
             gt=Config["qrcode"]["min-size"].as_number(),  # noqa:F821
             lt=Config["qrcode"]["max-size"].as_number(),  # noqa:F821
         ) = 200,
         logo: Optional[HostUrl] = None,
         level: QRCodeLevel = QRCodeLevel.M,
         bgcolor: Color = Color("FFFFFF"),
         fgcolor: Color = Color("000000"),
 ):
     icon_stream = None
     if logo is not None:
         async with BaseNetClient() as client:
             response = await client.get(
                 logo, headers={"user-agent": "HibiAPI@GitHub"}, timeout=6)
             response.raise_for_status()
         icon_stream = BytesIO(response.content)
     return cls(
         data=text,
         logo=logo,
         level=level,
         size=size,
         path=await cls._generate(
             text,
             size=size,
             level=level,
             icon_stream=icon_stream,
             bgcolor=bgcolor.as_hex(),
             fgcolor=fgcolor.as_hex(),
         ),
     )
示例#2
0
async def qrcode_api(
        request: Request,
        *,
        text: str,
        size: int = 200,
        logo: Optional[HostUrl] = None,
        encode: ReturnEncode = ReturnEncode.raw,
        level: QRCodeLevel = QRCodeLevel.M,
        bgcolor: Color = Color("FFFFFF"),
        fgcolor: Color = Color("000000"),
        fun: str = "qrcode",
):
    qr = await QRInfo.new(text,
                          size=size,
                          logo=logo,
                          level=level,
                          bgcolor=bgcolor,
                          fgcolor=fgcolor)
    qr.url = TempFile.to_url(request, qr.path)  # type:ignore
    """function {fun}(){document.write('<img class="qrcode" src="{url}"/>');}"""
    return (qr if encode == ReturnEncode.json else Response(
        content=qr.json(),
        media_type="application/json",
        headers={"Location": qr.url},
        status_code=302,
    ) if encode == ReturnEncode.raw else Response(
        content="{fun}({json})".format(json=qr.json(), fun=fun),
        media_type="text/javascript",
    ) if encode == ReturnEncode.jsc else Response(
        content="function " + fun +
        '''(){document.write('<img class="qrcode" src="''' + qr.url +
        """"/>');}""",
        media_type="text/javascript",
    ))
示例#3
0
async def qrcode_api(
    request: Request,
    *,
    text: str,
    size: int = 200,
    logo: Optional[HostUrl] = None,
    encode: ReturnEncode = ReturnEncode.raw,
    level: QRCodeLevel = QRCodeLevel.M,
    bgcolor: Color = Color("FFFFFF"),
    fgcolor: Color = Color("000000"),
    fun: str = "qrcode",
):
    qr = await QRInfo.new(
        text, size=size, logo=logo, level=level, bgcolor=bgcolor, fgcolor=fgcolor
    )
    qr.url = ParseResult(  # type:ignore
        scheme=request.url.scheme,
        netloc=request.url.netloc,
        path=f"temp/{qr.path.relative_to(TempFile.path)}",
        params="",
        query="",
        fragment="",
    ).geturl()
    return (
        qr
        if encode == ReturnEncode.json
        else Response(headers={"Location": qr.url}, status_code=302)
        if encode == ReturnEncode.raw
        else Response(content=f"{fun}({qr.json()})", media_type="text/javascript")
    )
示例#4
0
class Shape(ABC):
    z: float = field(default=None)
    c: int = field(default=None)
    t: int = field(default=None)
    fill_color: Color = field(default=Color((10, 10, 10, 0.1)))
    stroke_color: Color = field(default=Color((255, 255, 255, 1.0)))
    stroke_width: int = field(default=1)
    label: str = field(default=None)
def test_simple(ctx: DepContext):
    map_set_paths: MapSetPaths = ctx.get(MapSetPaths)
    map_set_io: MapSetIO = ctx.get(MapSetIO)
    map_set_cache: MapSetCache = ctx.get(MapSetCache)
    map_set_manager: MapSetManager = ctx.get(MapSetManager)

    assert map_set_io.get_map_set_uuid_to_name_mapping() == {}
    map_set = map_set_manager.create('Test1')
    assert map_set.name == 'Test1'

    map_set_file = map_set_paths.get_map_set_path(map_set.uuid)
    assert isfile(map_set_file)

    battle_maps = map_set.get_battle_maps()
    assert len(battle_maps) == 1

    battle_map_file = map_set_paths.get_battle_map_path(
        map_set.uuid, battle_maps[0].uuid)
    background_file = map_set_paths.get_background_path(
        map_set.uuid, battle_maps[0].uuid)
    assert isfile(battle_map_file)
    assert not isfile(background_file)

    map_set.name = 'Changed1'
    battle_maps[0].name = 'Changed2'
    battle_maps[0].set_background_image(media_type='image/svg+xml',
                                        image_data=SOME_SVG)
    battle_maps[0].process_token_action(
        TokenAction(action_type=TokenActionType.Added,
                    uuid=uuid4(),
                    token_type=0,
                    color=Color('Black'),
                    mark='23',
                    mark_color=Color('White'),
                    position=Coordinate(x=17, y=27),
                    rotation=1.2))
    map_set_manager.save(map_set)
    assert isfile(background_file)

    map_set_cache.delete(map_set)
    fresh_map_set = map_set_manager.get_by_uuid(map_set.uuid)
    assert fresh_map_set.name == 'Changed1'
    fresh_battle_maps = fresh_map_set.get_battle_maps()
    assert len(fresh_battle_maps) == 1
    assert fresh_battle_maps[0].name == 'Changed2'
    assert fresh_battle_maps[0].get_background_image() == SOME_SVG
    assert len(fresh_battle_maps[0].tokens)
    assert fresh_battle_maps[0].tokens[0].mark == '23'

    map_set_manager.delete(fresh_map_set)
    assert not isfile(map_set_file)
    assert not isfile(battle_map_file)
    assert not isfile(background_file)
示例#6
0
def test_as_hsl_tuple():
    c = Color('016997')
    h, s, l, a = c.as_hsl_tuple(alpha=True)
    assert almost_equal_floats(h, 0.551, delta=0.01)
    assert almost_equal_floats(s, 0.986, delta=0.01)
    assert almost_equal_floats(l, 0.298, delta=0.01)
    assert a == 1

    assert c.as_hsl_tuple(alpha=False) == c.as_hsl_tuple(alpha=None) == (h, s, l)

    c = Color((3, 40, 50, 0.5))
    hsla = c.as_hsl_tuple(alpha=None)
    assert len(hsla) == 4
    assert hsla[3] == 0.5
示例#7
0
def get_test_move(data=None):
    if data is None:
        data = {}
    raw_data = {
        'action_type': TokenActionType.Added,
        'uuid': uuid4(),
        'token_type': 17,
        'color': Color('Black'),
        'mark': '23',
        'mark_color': Color('White'),
        'position': Coordinate(x=27, y=13),
        'rotation': 2.3,
        **data
    }
    return TokenAction(**raw_data)
示例#8
0
def test_draw_bg(config):
    config.text_fields[0].bg = Color("#ff000066")
    config.text_fields[0].padding = fmcardgen.config.PaddingConfig(
        horizontal=10, vertical=10
    )
    im = fmcardgen.draw.draw({"title": "Hello World"}, config)
    assert_images_equal(im, Image.open("test_draw_bg_expected.png"))
示例#9
0
文件: main.py 项目: mausconi/saasify
class StyleCloudRequest(BaseModel):
    url: str = Schema(None, description="URL of webpage to extract text")
    text: str = Schema(None, description="Source text")
    size: int = Schema(512, description="Output width and height in pixels")
    icon_name: FontAwesomeIcon = Schema(
        "fas fa-grin",
        description=
        "[Font Awesome](https://fontawesome.com/icons?d=gallery&m=free) icon mask",
        alias="icon",
    )
    palette: Palette = Schema(
        "cartocolors.qualitative.Bold_6",
        description=
        "Color palette to use from [palettable](https://jiffyclub.github.io/palettable/)",
    )
    background_color: Color = Color("white")
    max_font_size: int = 200
    max_words: int = Schema(
        2000,
        description="Maximum number of words to include in the stylecloud",
        gt=0)
    stopwords: bool = Schema(
        True, description="Boolean to filter out common stopwords")
    gradient: Gradient = Schema(
        "horizontal",
        description="Direction of gradient. Set to 'none' to disable gradient.",
    )
示例#10
0
async def test_bson_encoders_filed_types():
    custom = DocumentWithBsonEncodersFiledsTypes(
        color="7fffd4", timestamp=datetime.datetime.utcnow())
    c = await custom.insert()
    c_fromdb = await DocumentWithBsonEncodersFiledsTypes.find_one(
        DocumentWithBsonEncodersFiledsTypes.color == Color("7fffd4"))
    assert c_fromdb.color.as_hex() == c.color.as_hex()
示例#11
0
文件: character.py 项目: avrae/avrae
 def set(self, new_value):
     if self.type == 'color':
         try:
             color_val = Color(new_value)
             r, g, b = color_val.as_rgb_tuple(alpha=False)
             val = (r << 16) + (g << 8) + b
         except (ValueError, TypeError):
             return f'\u274c Invalid {self.description}. ' \
                    f'Use `{self.ctx.prefix}csettings {self.setting_key} reset` to reset it to {self.default}.'
     elif self.type == 'number':
         try:
             val = int(new_value)
         except (ValueError, TypeError):
             return f'\u274c Invalid {self.description}. ' \
                    f'Use `{self.ctx.prefix}csettings {self.setting_key} reset` to reset it to {self.default}.'
     elif self.type == 'boolean':
         try:
             val = get_positivity(new_value)
         except AttributeError:
             return f'\u274c Invalid {self.description}.' \
                    f'Use `{self.ctx.prefix}csettings {self.setting_key} false` to reset it.'
     else:
         log.warning(f"No setting type for {self.type} found")
         return
     try:
         setattr(self.character.options, self.setting_key, val)
     except ValidationError as e:
         return f"\u274c Invalid {self.description}: {e!s}.\n" \
                f"Use `{self.ctx.prefix}csettings {self.setting_key} reset` to reset it to {self.default}."
     return f"\u2705 {self.description.capitalize()} set to {self.display_func(val)}.\n"
示例#12
0
def test_draw_wrapped(config: CardGenConfig):
    config.text_fields[0].font_size = 40
    config.text_fields[0].wrap = True
    config.text_fields[0].max_width = 400
    config.text_fields[0].bg = Color("#00ff0066")
    fm = {"title": "This is a longer title that I expect to wrap some."}
    im = fmcardgen.draw.draw(fm, config)
    assert_images_equal(im, Image.open("test_draw_wrapped.png"))
def test_as_rgb_tuple():
    assert Color((1, 2, 3)).as_rgb_tuple(alpha=None) == (1, 2, 3)
    assert Color((1, 2, 3, 1)).as_rgb_tuple(alpha=None) == (1, 2, 3)
    assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=None) == (1, 2, 3, 0.3)
    assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=None) == (1, 2, 3, 0.3)

    assert Color((1, 2, 3)).as_rgb_tuple(alpha=False) == (1, 2, 3)
    assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=False) == (1, 2, 3)

    assert Color((1, 2, 3)).as_rgb_tuple(alpha=True) == (1, 2, 3, 1)
    assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=True) == (1, 2, 3, 0.3)
示例#14
0
class ConfigDefaults(BaseModel):
    font: Union[str, Path] = "default"
    font_size: int = 40
    fg: Color = Color((0, 0, 0))
    bg: Optional[Color] = None
    padding: int = 0

    class Config:
        extra = "forbid"
        validate_assignment = True
def test_as_hex():
    assert Color((1, 2, 3)).as_hex() == '#010203'
    assert Color((119, 119, 119)).as_hex() == '#777'
    assert Color((119, 0, 238)).as_hex() == '#70e'
    assert Color('B0B').as_hex() == '#b0b'
    assert Color((1, 2, 3, 0.123456)).as_hex() == '#0102031f'
    assert Color((1, 2, 3, 0.1)).as_hex() == '#0102031a'
示例#16
0
def test_as_named():
    assert Color((0, 255, 255)).as_named() == 'cyan'
    assert Color('#808000').as_named() == 'olive'
    assert Color('hsl(180, 100%, 50%)').as_named() == 'cyan'

    assert Color((240, 248, 255)).as_named() == 'aliceblue'
    with pytest.raises(ValueError) as exc_info:
        Color((1, 2, 3)).as_named()
    assert exc_info.value.args[0] == 'no named color found, use fallback=True, as_hex() or as_rgb()'

    assert Color((1, 2, 3)).as_named(fallback=True) == '#010203'
    assert Color((1, 2, 3, 0.1)).as_named(fallback=True) == '#0102031a'
示例#17
0
def test_pretty_color():
    c = Color('red')
    assert str(c) == 'red'
    assert repr(c) == "Color('red', rgb=(255, 0, 0))"
    assert list(c.__pretty__(lambda x: f'fmt: {x!r}')) == [
        'Color(',
        1,
        "fmt: 'red'",
        ',',
        0,
        'rgb=',
        'fmt: (255, 0, 0)',
        ',',
        0,
        -1,
        ')',
    ]
def test_model_validation():
    class Model(BaseModel):
        color: Color

    assert Model(color='red').color.as_hex() == '#f00'
    assert Model(color=Color('red')).color.as_hex() == '#f00'
    with pytest.raises(ValidationError) as exc_info:
        Model(color='snot')
    assert exc_info.value.errors() == [{
        'loc': ('color', ),
        'msg':
        'value is not a valid color: string not recognised as a valid color',
        'type': 'value_error.color',
        'ctx': {
            'reason': 'string not recognised as a valid color'
        },
    }]
示例#19
0
from pydantic.json import pydantic_encoder, timedelta_isoformat
from pydantic.types import DirectoryPath, FilePath, SecretBytes, SecretStr


class MyEnum(Enum):
    foo = 'bar'
    snap = 'crackle'


@pytest.mark.parametrize(
    'input,output',
    [
        (UUID('ebcdab58-6eb8-46fb-a190-d07a33e9eac8'),
         '"ebcdab58-6eb8-46fb-a190-d07a33e9eac8"'),
        (IPv4Address('192.168.0.1'), '"192.168.0.1"'),
        (Color('#000'), '"black"'),
        (Color((1, 12, 123)), '"#010c7b"'),
        (SecretStr('abcd'), '"**********"'),
        (SecretStr(''), '""'),
        (SecretBytes(b'xyz'), '"**********"'),
        (SecretBytes(b''), '""'),
        (IPv6Address('::1:0:1'), '"::1:0:1"'),
        (IPv4Interface('192.168.0.0/24'), '"192.168.0.0/24"'),
        (IPv6Interface('2001:db00::/120'), '"2001:db00::/120"'),
        (IPv4Network('192.168.0.0/24'), '"192.168.0.0/24"'),
        (IPv6Network('2001:db00::/120'), '"2001:db00::/120"'),
        (datetime.datetime(2032, 1, 1, 1, 1), '"2032-01-01T01:01:00"'),
        (datetime.datetime(2032, 1, 1, 1, 1, tzinfo=datetime.timezone.utc),
         '"2032-01-01T01:01:00+00:00"'),
        (datetime.datetime(2032, 1, 1), '"2032-01-01T00:00:00"'),
        (datetime.time(12, 34, 56), '"12:34:56"'),
def test_color_fail(color):
    with pytest.raises(ColorError):
        Color(color)
def test_color_success(raw_color, as_tuple):
    c = Color(raw_color)
    assert c.as_rgb_tuple() == as_tuple
    assert c.original() == raw_color
def test_str_repr():
    assert str(Color('red')) == 'red'
    assert repr(Color('red')) == "Color('red', rgb=(255, 0, 0))"
    assert str(Color((1, 2, 3))) == '#010203'
    assert repr(Color((1, 2, 3))) == "Color('#010203', rgb=(1, 2, 3))"
def test_as_hsl():
    assert Color('bad').as_hsl() == 'hsl(260, 43%, 77%)'
    assert Color((1, 2, 3, 0.123456)).as_hsl() == 'hsl(210, 50%, 1%, 0.12)'
    assert Color('hsl(260, 43%, 77%)').as_hsl() == 'hsl(260, 43%, 77%)'
def test_as_rgb():
    assert Color('bad').as_rgb() == 'rgb(187, 170, 221)'
    assert Color((1, 2, 3, 0.123456)).as_rgb() == 'rgba(1, 2, 3, 0.12)'
    assert Color((1, 2, 3, 0.1)).as_rgb() == 'rgba(1, 2, 3, 0.1)'
示例#25
0
def test_str_repr():
    assert str(Color('red')) == 'red'
    assert repr(Color('red')) == "<Color('red', (255, 0, 0))>"
    assert str(Color((1, 2, 3))) == '#010203'
    assert repr(Color((1, 2, 3))) == "<Color('#010203', (1, 2, 3))>"
示例#26
0
    def run(self):
        logger.info("Validating requirements...")  # You may use the logger function to log info

        # It is a good practice to verify all the requirements before running the analysis
        # This will verify that all the non optional requirements are provided
        if len(self.list_unmet_requirements()):
            # we can use the logger to report errors
            logger.error(f"The following metadata requirements ara not met: {self.list_unmet_requirements()}")
            return False  # The run method should return False upon unsuccessful execution

        logger.info("Finding lines...")

        # Lets find some lines in the image using skimage

        # If you remember, we did not provide a default value for the line_length. This does not make much sense
        # but for the sake of demonstration. You can access the metadata as properties of the analysis (self) input
        if not self.input.line_length.value:   # We check if the value of the line_length is None
            self.input.line_length.value = 50  # and if it is, we give it a value

        lines = probabilistic_hough_line(
            image=self.input.data['image_with_lines'],  # The input image data is accessible through the input.data
            threshold=self.get_metadata_values('threshold'),  # You may access the metadata like this too
            line_length=self.input.line_length.value,
        )

        # 'lines' is now a list of lines defined by the coordinates ((x1, y1), (x2, y2))

        # We may add some rois to the output
        shapes = [model.Line(x1=x1, y1=y1, x2=x2, y2=y2, stroke_color=Color('red'))  # With some color
                  for (x1, y1), (x2, y2) in lines]
        self.output.append(model.Roi(name='lines',
                                     description='lines found using a progressive probabilistic hough transform',
                                     shapes=shapes))

        # We may create a table with the coordinates...
        lines_df = DataFrame.from_records([(a, b, c, d) for (a, b), (c, d) in lines],
                                          columns=['x_1', 'y_1', 'x_2', 'y_2'])

        # ... and add some very interesting measurements
        lines_df['length'] = lines_df.apply(lambda l: distance.euclidean([l.x_1, l.y_1], [l.x_2, l.y_2]), axis=1)
        lines_df['angle'] = lines_df.apply(lambda l: atan2(l.x_1 - l.x_2, l.y_1 - l.y_2), axis=1)

        # We append the dataframe into the output
        self.output.append(model.Table(name='lines_table',
                                       description='Dataframe containing coordinates, length and angle for every line',
                                       table=lines_df))

        # Lets extract some statistics...
        stats = {'mean_length': lines_df.length.mean(),
                 'median_length': lines_df.length.median(),
                 'std_length': lines_df.length.std(),
                 'mean_angle': lines_df.angle.mean(),
                 'median_angle': lines_df.angle.median(),
                 'std_angle': lines_df.angle.std()}

        # ... and save them as key-value pairs
        self.output.append(model.KeyValues(name='stats',
                                           description='Some basic statistics about the lines found',
                                           key_values=stats))

        # And that's about it. Don't forget to return True at the end
        return True
示例#27
0
from pydantic import BaseModel, ValidationError
from pydantic.color import Color

c = Color('ff00ff')
print(c.as_named())
print(c.as_hex())
c2 = Color('green')
print(c2.as_rgb_tuple())
print(c2.original())
print(repr(Color('hsl(180, 100%, 50%)')))


class Model(BaseModel):
    color: Color


print(Model(color='purple'))
try:
    Model(color='hello')
except ValidationError as e:
    print(e)
示例#28
0
    def run(self):
        """Analyzes images of sub-resolution beads in order to extract data on the optical
        performance of the microscope.
        """
        logger.info("Validating requirements...")
        if not self.validate_requirements():
            logger.error("Metadata requirements ara not valid")
            return False

        logger.info("Analyzing spots image...")

        # Verify that image is not saturated
        if np.issubdtype(self.input.data["beads_image"].dtype, np.integer):
            if self.input.data["beads_image"].max() == np.iinfo(
                    self.input.data["beads_image"].dtype).max:
                logger.error(
                    "Image is saturated. No attempt to find beads will be done."
                )
                return False
        elif np.issubdtype(self.input.data["beads_image"].dtype, np.float):
            if self.input.data["beads_image"].max() == np.finfo(
                    self.input.data["beads_image"].dtype).max:
                logger.error(
                    "Image is saturated. No attempt to find beads will be done."
                )
                return False

        # Get some analysis_config parameters
        pixel_size_units = self.get_metadata_units("pixel_size")
        pixel_size = self.get_metadata_values("pixel_size")
        min_bead_distance = self.estimate_min_bead_distance()

        # Remove all negative intensities. eg. 3D-SIM images may contain negative values.
        image_data = np.clip(self.input.data["beads_image"],
                             a_min=0,
                             a_max=None)

        # Validating nyquist
        try:
            if pixel_size[1] > (
                    2 *
                    self.get_metadata_values("theoretical_fwhm_lateral_res")):
                module_logger.warning(
                    "Nyquist criterion is not fulfilled in the lateral direction"
                )
            if pixel_size[0] > (
                    2 *
                    self.get_metadata_values("theoretical_fwhm_axial_res")):
                module_logger.warning(
                    "Nyquist criterion is not fulfilled in the axial direction"
                )
        except (TypeError, IndexError) as e:
            module_logger.error(
                "Could not validate Nyquist sampling criterion")

        (
            bead_images,
            positions,
            positions_edge_discarded,
            positions_proximity_discarded,
            positions_intensity_discarded,
        ) = self._find_beads(
            image=image_data,
            min_distance=min_bead_distance,
            sigma=self.get_metadata_values('sigma'),
        )

        for i, bead_image in enumerate(bead_images):
            self.output.append(
                model.Image(name=f"bead_nr{i:02d}",
                            description=f"PSF bead crop for bead nr {i}",
                            data=np.expand_dims(bead_image, axis=(1, 2))))

        for i, position in enumerate(positions):
            self.output.append(
                model.Roi(name=f"bead_nr{i:02d}_centroid",
                          description=f"Weighted centroid of bead nr {i}",
                          shapes=[
                              model.Point(z=position[0].item(),
                                          y=position[1].item(),
                                          x=position[2].item(),
                                          stroke_color=Color((0, 255, 0, .0)),
                                          fill_color=Color((50, 255, 50, .1)))
                          ]))

        edge_points = [
            model.Point(z=pos[0].item(),
                        y=pos[1].item(),
                        x=pos[2].item(),
                        stroke_color=Color((255, 0, 0, .6)),
                        fill_color=Color((255, 50, 50, .1)))
            for pos in positions_edge_discarded
        ]
        self.output.append(
            model.Roi(
                name="Discarded_edge",
                description=
                "Beads discarded for being to close to the edge of the image",
                shapes=edge_points))

        proximity_points = [
            model.Point(z=pos[0].item(),
                        y=pos[1].item(),
                        x=pos[2].item(),
                        stroke_color=Color((255, 0, 0, .6)),
                        fill_color=Color((255, 50, 50, .1)))
            for pos in positions_proximity_discarded
        ]
        self.output.append(
            model.Roi(
                name="Discarded_proximity",
                description="Beads discarded for being to close to each other",
                shapes=proximity_points))

        intensity_points = [
            model.Point(z=pos[0].item(),
                        y=pos[1].item(),
                        x=pos[2].item(),
                        stroke_color=Color((255, 0, 0, .6)),
                        fill_color=Color((255, 50, 50, .1)))
            for pos in positions_intensity_discarded
        ]
        self.output.append(
            model.Roi(
                name="Discarded_intensity",
                description="Beads discarded for being to intense or to weak. "
                "Suspected not being single beads",
                shapes=intensity_points))

        # Generate profiles and measure FWHM
        raw_profiles = []
        fitted_profiles = []
        fwhm_values = []
        for bead_image in bead_images:
            opr, fpr, fwhm = self._analyze_bead(bead_image)
            raw_profiles.append(opr)
            fitted_profiles.append(fpr)
            fwhm = tuple(f * ps for f, ps in zip(fwhm, pixel_size))
            fwhm_values.append(fwhm)

        properties_df = DataFrame()
        properties_df["bead_nr"] = range(len(bead_images))
        properties_df["max_intensity"] = [e.max() for e in bead_images]
        properties_df["min_intensity"] = [e.min() for e in bead_images]
        properties_df["z_centroid"] = [e[0] for e in positions]
        properties_df["y_centroid"] = [e[1] for e in positions]
        properties_df["x_centroid"] = [e[2] for e in positions]
        properties_df["centroid_units"] = "PIXEL"
        properties_df["z_fwhm"] = [e[0] for e in fwhm_values]
        properties_df["y_fwhm"] = [e[1] for e in fwhm_values]
        properties_df["x_fwhm"] = [e[2] for e in fwhm_values]
        properties_df["fwhm_units"] = pixel_size_units

        self.output.append(
            model.Table(name="Analysis_PSF_properties",
                        description="Properties associated with the analysis",
                        table=properties_df))

        profiles_z_df = DataFrame()
        profiles_y_df = DataFrame()
        profiles_x_df = DataFrame()

        for i, (raw_profile,
                fitted_profile) in enumerate(zip(raw_profiles,
                                                 fitted_profiles)):
            profiles_z_df[f"raw_z_profile_bead_{i:02d}"] = raw_profile[0]
            profiles_z_df[f"fitted_z_profile_bead_{i:02d}"] = fitted_profile[0]
            profiles_y_df[f"raw_y_profile_bead_{i:02d}"] = raw_profile[1]
            profiles_y_df[f"fitted_y_profile_bead_{i:02d}"] = fitted_profile[1]
            profiles_x_df[f"raw_x_profile_bead_{i:02d}"] = raw_profile[2]
            profiles_x_df[f"fitted_x_profile_bead_{i:02d}"] = fitted_profile[2]

        self.output.append(
            model.Table(
                name="Analysis_PSF_Z_profiles",
                description="Raw and fitted profiles along Z axis of beads",
                table=profiles_z_df))

        self.output.append(
            model.Table(
                name="Analysis_PSF_Y_profiles",
                description="Raw and fitted profiles along Y axis of beads",
                table=profiles_y_df))

        self.output.append(
            model.Table(
                name="Analysis_PSF_X_profiles",
                description="Raw and fitted profiles along X axis of beads",
                table=profiles_x_df))

        key_values = {"nr_of_beads_analyzed": positions.shape[0]}

        if key_values["nr_of_beads_analyzed"] == 0:
            key_values["resolution_mean_fwhm_z"] = "None"
            key_values["resolution_mean_fwhm_y"] = "None"
            key_values["resolution_mean_fwhm_x"] = "None"
            key_values["resolution_mean_fwhm_units"] = "None"
        else:
            key_values["resolution_mean_fwhm_z"] = properties_df[
                "z_fwhm"].mean()
            key_values["resolution_median_fwhm_z"] = properties_df[
                "z_fwhm"].median()
            key_values["resolution_stdev_fwhm_z"] = properties_df[
                "z_fwhm"].std()
            key_values["resolution_mean_fwhm_y"] = properties_df[
                "y_fwhm"].mean()
            key_values["resolution_median_fwhm_y"] = properties_df[
                "y_fwhm"].median()
            key_values["resolution_stdev_fwhm_y"] = properties_df[
                "y_fwhm"].std()
            key_values["resolution_mean_fwhm_x"] = properties_df[
                "x_fwhm"].mean()
            key_values["resolution_median_fwhm_x"] = properties_df[
                "x_fwhm"].median()
            key_values["resolution_stdev_fwhm_x"] = properties_df[
                "x_fwhm"].std()
        key_values[
            "resolution_theoretical_fwhm_lateral"] = self.get_metadata_values(
                'theoretical_fwhm_lateral_res')
        key_values[
            "resolution_theoretical_fwhm_lateral_units"] = self.get_metadata_units(
                'theoretical_fwhm_lateral_res')
        key_values[
            "resolution_theoretical_fwhm_axial"] = self.get_metadata_values(
                'theoretical_fwhm_axial_res')
        key_values[
            "resolution_theoretical_fwhm_axial_units"] = self.get_metadata_units(
                'theoretical_fwhm_axial_res')

        self.output.append(
            model.KeyValues(name='Measurements_results',
                            description='Output measurements',
                            key_values=key_values))

        return True