Пример #1
0
    async def gridify(self, ctx, *args):
        faction = None
        color = 0x808080
        iter_args = iter(args)
        name = next(iter_args, None)
        while name in ["-f", "-c"]:
            if name == "-f":
                fac = next(iter_args, None)
                if fac is None:
                    await ctx.send(ctx.s("error.missing_arg_faction"))
                    return
                f = sql.guild_get_by_faction_name_or_alias(fac)
                if not faction:
                    await ctx.send(ctx.s("error.faction_not_found"))
                    return
            if name == "-c":
                try:
                    color = abs(int(next(iter_args, None), 16) % 0xFFFFFF)
                    name = next(iter_args, None)
                except ValueError:
                    await ctx.send(ctx.s("error.invalid_color"))
                    return

        def parse_zoom(z):
            try:
                if type(z) is int:
                    return z
                if type(z) is str:
                    if z.startswith("#"):
                        z = z[1:]
                    return int(z)
                if z is None:
                    return 8
            except ValueError:
                return 8

        t = sql.template_get_by_name(
            faction.id, name) if faction else sql.template_get_by_name(
                ctx.guild.id, name)
        if t:
            log.info("(T:{} | GID:{})".format(t.name, t.gid))
            data = await http.get_template(t.url, t.name)
            max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
            zoom = max(1, min(parse_zoom(next(iter_args, 1)), max_zoom))
            template = await render.gridify(data, color, zoom)
        else:
            att = await utils.verify_attachment(ctx)
            data = io.BytesIO()
            await att.save(data)
            max_zoom = int(math.sqrt(4000000 // (att.width * att.height)))
            zoom = max(1, min(parse_zoom(name), max_zoom))
            template = await render.gridify(data, color, zoom)

        with io.BytesIO() as bio:
            template.save(bio, format="PNG")
            bio.seek(0)
            f = discord.File(bio, "gridded.png")
            await ctx.send(file=f)
Пример #2
0
    async def gridify(self, ctx, *args):
        log.info(f"g!gridify run in {ctx.guild.name} with args: {args}")

        # Argument Parsing
        parser = GlimmerArgumentParser(ctx)
        parser.add_argument("-f",
                            "--faction",
                            default=None,
                            action=FactionAction)
        parser.add_argument("-c",
                            "--color",
                            default=0x808080,
                            action=ColorAction)
        parser.add_argument("-z", "--zoom", type=int, default=1)

        # Pre-Parsing
        if len(args) == 0:
            name = None
            a = args
        elif args[0][0] != "-":
            name = args[0]
            a = args[1:]
        else:
            name = None
            a = args

        try:
            a = vars(parser.parse_args(a))
        except TypeError:
            return

        faction = a["faction"]
        color = a["color"]
        zoom = a["zoom"]

        gid = ctx.guild.id if not faction else faction.id
        t = sql.template_get_by_name(gid, name)

        if name:
            if t:
                log.info("(T:{} | GID:{})".format(t.name, t.gid))
                data = await http.get_template(t.url, t.name)
                max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
                zoom = max(1, min(zoom, max_zoom))
                template = await render.gridify(data, color, zoom)
            else:
                raise TemplateNotFoundError(gid, name)
        else:
            att = await verify_attachment(ctx)
            data = io.BytesIO()
            await att.save(data)
            max_zoom = int(math.sqrt(4000000 // (att.width * att.height)))
            zoom = max(1, min(zoom, max_zoom))
            template = await render.gridify(data, color, zoom)

        with io.BytesIO() as bio:
            template.save(bio, format="PNG")
            bio.seek(0)
            f = discord.File(bio, "gridded.png")
            await ctx.send(file=f)
Пример #3
0
async def _quantize(ctx, args, canvas, palette):
    gid = ctx.guild.id
    iter_args = iter(args)
    name = next(iter_args, None)
    if name == "-f":
        faction = sql.guild_get_by_faction_name_or_alias(next(iter_args, None))
        if not faction:
            raise errors.FactionNotFound
        gid = faction.id
        name = next(iter_args, None)
    t = sql.template_get_by_name(gid, name)

    data = None
    if t:
        log.debug("(T:{} | GID:{})".format(t.name, t.gid))
        if t.canvas == canvas:
            raise errors.IdempotentActionError
        data = await http.get_template(t.url)
    else:
        att = await utils.verify_attachment(ctx)
        if att:
            data = io.BytesIO()
            await att.save(data)

    if data:
        template, bad_pixels = await render.quantize(data, palette)

        with io.BytesIO() as bio:
            template.save(bio, format="PNG")
            bio.seek(0)
            f = discord.File(bio, "template.png")
            return await ctx.send(ctx.s("canvas.quantize").format(bad_pixels), file=f)
Пример #4
0
    async def template_snapshot_add(self, ctx, base_template,
                                    snapshot_template):
        if not utils.is_template_admin(ctx) and not utils.is_admin(ctx):
            await ctx.send(ctx.s("template.err.not_owner"))
            return

        base = sql.template_get_by_name(ctx.guild.id, base_template)
        target = sql.template_get_by_name(ctx.guild.id, snapshot_template)

        if base == None:
            await ctx.send("The base template does not exist.")
            return
        if target == None:
            await ctx.send("The snapshot template does not exist.")
            return

        sql.snapshot_add(ctx.guild.id, base_template, snapshot_template)
        await ctx.send("Snapshot added!")
Пример #5
0
 async def check_for_duplicate_by_name(ctx, template):
     dup = sql.template_get_by_name(ctx.guild.id, template.name)
     if dup:
         if template.owner_id != ctx.author.id and not utils.is_admin(ctx):
             await ctx.send(ctx.s("template.err.name_exists"))
             return False
         print(dup.x)
         q = ctx.s("template.name_exists_ask_replace") \
             .format(dup.name, canvases.pretty_print[dup.canvas], dup.x, dup.y)
         return await utils.yes_no(ctx, q)
Пример #6
0
 async def template_remove(self, ctx, name):
     t = sql.template_get_by_name(ctx.guild.id, name)
     if not t:
         raise TemplateNotFoundError
     log.info("(T:{})".format(t.name, t.gid))
     if t.owner_id != ctx.author.id and not utils.is_template_admin(
             ctx) and not utils.is_admin(ctx):
         await ctx.send(ctx.s("template.err.not_owner"))
         return
     sql.template_delete(t.gid, t.name)
     await ctx.send(ctx.s("template.remove").format(name))
Пример #7
0
    async def check_for_duplicate_by_name(ctx, template):
        """Checks for duplicates by name, will bypass and signal to overwrite if told to.

        Arguments:
        ctx - commands.Context.
        template - A template object.

        Returns:
        A boolean or nothing.
        """
        dup = sql.template_get_by_name(ctx.guild.id, template.name)
        if dup:
            if template.owner_id != ctx.author.id and not utils.is_admin(ctx):
                await ctx.send(ctx.s("template.err.name_exists"))
                return False
            q = ctx.s("template.name_exists_ask_replace") \
                .format(dup.name, canvases.pretty_print[dup.canvas], dup.x, dup.y)
            yesnomenu = await utils.yes_no(ctx, q)
            if yesnomenu == True:
                return True
            else:
                await ctx.send(ctx.s("template.menuclose"))
                return False
Пример #8
0
    async def template_info(self, ctx, *args):
        gid = ctx.guild.id
        iter_args = iter(args)
        name = next(iter_args, 1)
        image_only = False
        if name == "-r":
            image_only = True
            name = next(iter_args, 1)
        if name == "-f":
            fac = next(iter_args, None)
            if fac is None:
                await ctx.send(ctx.s("error.missing_arg_faction"))
                return
            faction = sql.guild_get_by_faction_name_or_alias(fac)
            if not faction:
                raise FactionNotFoundError
            gid = faction.id
            name = next(iter_args, 1)
        else:
            faction = sql.guild_get_by_id(gid)
        t = sql.template_get_by_name(gid, name)
        if not t:
            raise TemplateNotFoundError

        if image_only:
            zoom = next(iter_args, 1)
            try:
                if type(zoom) is not int:
                    if zoom.startswith("#"):
                        zoom = zoom[1:]
                    zoom = int(zoom)
            except ValueError:
                zoom = 1
            max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
            zoom = max(1, min(zoom, max_zoom))

            img = render.zoom(await http.get_template(t.url, t.name), zoom)

            with io.BytesIO() as bio:
                img.save(bio, format="PNG")
                bio.seek(0)
                f = discord.File(bio, t.name + ".png")
                await ctx.send(file=f)
            return

        canvas_name = canvases.pretty_print[t.canvas]
        coords = "({}, {})".format(t.x, t.y)
        dimensions = "{} x {}".format(t.width, t.height)
        size = t.size
        visibility = ctx.s("bot.private") if bool(
            t.private) else ctx.s("bot.public")
        owner = self.bot.get_user(t.owner_id)
        if owner is None:
            added_by = ctx.s("error.account_deleted")
        else:
            added_by = owner.name + "#" + owner.discriminator
        date_added = datetime.date.fromtimestamp(
            t.date_created).strftime("%d %b, %Y")
        date_modified = datetime.date.fromtimestamp(
            t.date_updated).strftime("%d %b, %Y")
        color = faction.faction_color
        description = "[__{}__]({})".format(
            ctx.s("template.link_to_canvas"),
            canvases.url_templates[t.canvas].format(*t.center()))

        if size == 0:
            t.size = await render.calculate_size(await http.get_template(
                t.url, t.name))
            sql.template_update(t)

        e = discord.Embed(title=t.name, color=color, description=description) \
            .set_image(url=t.url) \
            .add_field(name=ctx.s("bot.canvas"), value=canvas_name, inline=True) \
            .add_field(name=ctx.s("bot.coordinates"), value=coords, inline=True) \
            .add_field(name=ctx.s("bot.dimensions"), value=dimensions, inline=True) \
            .add_field(name=ctx.s("bot.size"), value=size, inline=True) \
            .add_field(name=ctx.s("bot.visibility"), value=visibility, inline=True) \
            .add_field(name=ctx.s("bot.added_by"), value=added_by, inline=True) \
            .add_field(name=ctx.s("bot.date_added"), value=date_added, inline=True) \
            .add_field(name=ctx.s("bot.date_modified"), value=date_modified, inline=True)

        if faction.id != ctx.guild.id and faction.faction_name:
            e = e.set_author(name=faction.faction_name,
                             icon_url=faction.faction_emblem
                             or discord.Embed.Empty)

        await ctx.send(embed=e)
Пример #9
0
    async def diff(self, ctx, *args):
        if len(args) < 1:
            return
        list_pixels = False
        iter_args = iter(args)
        a = next(iter_args, None)
        if a == "-e":
            list_pixels = True
            a = next(iter_args, None)
        if a == "-f":
            fac = next(iter_args, None)
            if fac is None:
                await ctx.send(ctx.s("error.missing_arg_faction"))
                return
            f = sql.guild_get_by_faction_name_or_alias(fac)
            if not f:
                await ctx.send(ctx.s("error.faction_not_found"))
                return
            name = next(iter_args, None)
            zoom = next(iter_args, 1)
            t = sql.template_get_by_name(f.id, name)
        else:
            name = a
            zoom = next(iter_args, 1)
            t = sql.template_get_by_name(ctx.guild.id, name)

        try:
            if type(zoom) is not int:
                if zoom.startswith("#"):
                    zoom = zoom[1:]
                zoom = int(zoom)
        except ValueError:
            zoom = 1

        if t:
            async with ctx.typing():
                log.info("(T:{} | GID:{})".format(t.name, t.gid))
                data = await http.get_template(t.url, t.name)
                max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
                zoom = max(1, min(zoom, max_zoom))

                fetchers = {
                    'pixelcanvas': render.fetch_pixelcanvas,
                    'pixelzone': render.fetch_pixelzone,
                    'pxlsspace': render.fetch_pxlsspace
                }

                diff_img, tot, err, bad, err_list \
                    = await render.diff(t.x, t.y, data, zoom, fetchers[t.canvas], colors.by_name[t.canvas])

                done = tot - err
                perc = done / tot
                if perc < 0.00005 and done > 0:
                    perc = ">0.00%"
                elif perc >= 0.99995 and err > 0:
                    perc = "<100.00%"
                else:
                    perc = "{:.2f}%".format(perc * 100)
                out = ctx.s("canvas.diff") if bad == 0 else ctx.s(
                    "canvas.diff_bad_color")
                out = out.format(done, tot, err, perc, bad=bad)

                with io.BytesIO() as bio:
                    diff_img.save(bio, format="PNG")
                    bio.seek(0)
                    f = discord.File(bio, "diff.png")
                    await ctx.send(content=out, file=f)

                if list_pixels and len(err_list) > 0:
                    out = ["```xl"]
                    for p in err_list:
                        x, y, current, target = p
                        current = ctx.s("color.{}.{}".format(
                            t.canvas, current))
                        target = ctx.s("color.{}.{}".format(t.canvas, target))
                        out.append("({}, {}) is {}, should be {}".format(
                            x + t.x, y + t.y, current, target))
                    if err > 15:
                        out.append("...")
                    out.append("```")
                    await ctx.send('\n'.join(out))

                return
        await ctx.invoke_default("diff")
Пример #10
0
    async def preview(self, ctx, *args):
        if len(args) < 1:
            return
        preview_template_region = False
        iter_args = iter(args)
        a = next(iter_args, None)
        if a == "-t":
            preview_template_region = True
            a = next(iter_args, None)
        if a == "-f":
            fac = next(iter_args, None)
            if fac is None:
                await ctx.send(ctx.s("error.missing_arg_faction"))
                return
            f = sql.guild_get_by_faction_name_or_alias(fac)
            if not f:
                await ctx.send(ctx.s("error.faction_not_found"))
                return
            name = next(iter_args, None)
            zoom = next(iter_args, 1)
            t = sql.template_get_by_name(f.id, name)
        else:
            name = a
            zoom = next(iter_args, 1)
            t = sql.template_get_by_name(ctx.guild.id, name)

        try:
            if type(zoom) is not int:
                if zoom.startswith("#"):
                    zoom = zoom[1:]
                zoom = int(zoom)
        except ValueError:
            zoom = 1

        if t:
            async with ctx.typing():
                log.info("(T:{} | GID:{})".format(t.name, t.gid))
                max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
                zoom = max(-8, min(zoom, max_zoom))

                fetchers = {
                    'pixelcanvas': render.fetch_pixelcanvas,
                    'pixelzone': render.fetch_pixelzone,
                    'pxlsspace': render.fetch_pxlsspace
                }

                if preview_template_region:
                    preview_img = await render.preview(*t.center(), zoom,
                                                       fetchers[t.canvas])
                else:
                    preview_img = await render.preview_template(
                        t, zoom, fetchers[t.canvas])

                with io.BytesIO() as bio:
                    preview_img.save(bio, format="PNG")
                    bio.seek(0)
                    f = discord.File(bio, "preview.png")
                    await ctx.send(file=f)

                return
        await ctx.invoke_default("preview")
Пример #11
0
    async def template_info(self, ctx, *args):
        # Order Parsing
        try:
            name = args[0]
        except TypeError:
            await ctx.send("Error: no arguments were provided.")
            return

        if re.match("-\D+", name) != None:
            name = args[-1]
            args = args[:-1]
        else:
            args = args[1:]

        # Argument Parsing
        parser = GlimmerArgumentParser(ctx)
        parser.add_argument("-r", "--raw", action="store_true")
        parser.add_argument("-f",
                            "--faction",
                            default=None,
                            action=FactionAction)
        parser.add_argument("-z", "--zoom", default=1)
        try:
            args = vars(parser.parse_args(args))
        except TypeError:
            return

        image_only = args["raw"]
        f = args["faction"]
        try:
            gid, faction = f.id, f
        except AttributeError:
            gid, faction = ctx.guild.id, sql.guild_get_by_id(ctx.guild.id)
        zoom = args["zoom"]

        t = sql.template_get_by_name(gid, name)
        if not t:
            raise TemplateNotFoundError(gid, name)

        if image_only:
            try:
                if type(zoom) is not int:
                    if zoom.startswith("#"):
                        zoom = zoom[1:]
                    zoom = int(zoom)
            except ValueError:
                zoom = 1
            max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
            zoom = max(1, min(zoom, max_zoom))

            img = render.zoom(await http.get_template(t.url, t.name), zoom)

            with io.BytesIO() as bio:
                img.save(bio, format="PNG")
                bio.seek(0)
                f = discord.File(bio, t.name + ".png")
                await ctx.send(file=f)
            return

        canvas_name = canvases.pretty_print[t.canvas]
        coords = "{}, {}".format(t.x, t.y)
        dimensions = "{} x {}".format(t.width, t.height)
        size = t.size
        visibility = ctx.s("bot.private") if bool(
            t.private) else ctx.s("bot.public")
        owner = self.bot.get_user(t.owner_id)
        if owner is None:
            added_by = ctx.s("error.account_deleted")
        else:
            added_by = owner.name + "#" + owner.discriminator
        date_added = datetime.date.fromtimestamp(
            t.date_created).strftime("%d %b, %Y")
        date_modified = datetime.date.fromtimestamp(
            t.date_updated).strftime("%d %b, %Y")
        color = faction.faction_color
        description = "[__{}__]({})".format(
            ctx.s("template.link_to_canvas"),
            canvases.url_templates[t.canvas].format(*t.center()))

        if size == 0:
            t.size = await render.calculate_size(await http.get_template(
                t.url, t.name))
            sql.template_update(t)

        e = discord.Embed(title=t.name, color=color, description=description) \
            .set_image(url=t.url) \
            .add_field(name=ctx.s("bot.canvas"), value=canvas_name, inline=True) \
            .add_field(name=ctx.s("bot.coordinates"), value=coords, inline=True) \
            .add_field(name=ctx.s("bot.dimensions"), value=dimensions, inline=True) \
            .add_field(name=ctx.s("bot.size"), value=size, inline=True) \
            .add_field(name=ctx.s("bot.visibility"), value=visibility, inline=True) \
            .add_field(name=ctx.s("bot.added_by"), value=added_by, inline=True) \
            .add_field(name=ctx.s("bot.date_added"), value=date_added, inline=True) \
            .add_field(name=ctx.s("bot.date_modified"), value=date_modified, inline=True)

        if faction.id != ctx.guild.id and faction.faction_name:
            e = e.set_author(name=faction.faction_name,
                             icon_url=faction.faction_emblem
                             or discord.Embed.Empty)

        await ctx.send(embed=e)
Пример #12
0
    async def template_update_pixelcanvas(self, ctx, *args):
        log.info(f"g!t update run in {ctx.guild.name} with args: {args}")

        try:
            name = args[0]
        except TypeError:
            await ctx.send(
                "Template not updated as no arguments were provided.")
            return

        if re.match("-\D+", name) != None:
            name = args[-1]
            args = args[:-1]
        else:
            args = args[1:]

        orig_template = sql.template_get_by_name(ctx.guild.id, name)
        if not orig_template:
            raise TemplateNotFoundError(ctx.guild.id, name)

        # Argument Parsing
        parser = GlimmerArgumentParser(ctx)
        parser.add_argument("-n", "--newName", nargs="?", default=None)
        parser.add_argument("-x", nargs="?", default=None)
        parser.add_argument("-y", nargs="?", default=None)
        # if -i not present, False
        # if no value after -i, True
        # if value after -i, capture
        parser.add_argument("-i",
                            "--image",
                            nargs="?",
                            const=True,
                            default=None)
        try:
            args = vars(parser.parse_args(args))
        except TypeError:
            return

        new_name = args["newName"]
        x = args["x"]
        y = args["y"]
        image = args["image"]

        out = []
        """Image is done first since I'm using the build_template method to update stuff,
        and I don't want anything to have changed in orig_template before I use it"""
        if image:
            # Update image
            url = None
            if not isinstance(image, bool):
                url = image
            url = await Template.select_url_update(ctx, url, out)
            if url is None:
                return  # Sending the end is handled in select_url_update if it fails

            try:
                t = await Template.build_template(ctx, orig_template.name,
                                                  orig_template.x,
                                                  orig_template.y, url,
                                                  "pixelcanvas")
            except TemplateHttpError:
                out.append(
                    f"Updating file failed: Could not access URL for template."
                )
                await Template.send_end(ctx, out)
                return
            except NoJpegsError:
                out.append(
                    f"Updating file failed: Seriously? A JPEG? Gross! Please create a PNG template instead."
                )
                await Template.send_end(ctx, out)
                return
            except NotPngError:
                out.append(
                    f"Updating file failed: That command requires a PNG image."
                )
                await Template.send_end(ctx, out)
                return
            except (PilImageError, UrlError):
                out.append(f"Updating file failed.")
                await Template.send_end(ctx, out)
                return

            if t is None:
                out.append(f"Updating file failed.")
                await Template.send_end(ctx, out)
                return

            # Could check for md5 duplicates here, maybe implement that later
            sql.template_kwarg_update(ctx.guild.id,
                                      orig_template.name,
                                      url=t.url,
                                      md5=t.md5,
                                      w=t.width,
                                      h=t.height,
                                      size=t.size,
                                      date_modified=int(time.time()))
            out.append(f"File updated.")

        if x:
            # Update x coord
            try:
                x = int(re.sub('[^0-9-]', '', x))
            except ValueError:
                out.append(
                    "Updating x failed, value provided was not a number.")
                await Template.send_end(ctx, out)
                return

            sql.template_kwarg_update(ctx.guild.id,
                                      orig_template.name,
                                      x=x,
                                      date_modified=int(time.time()))
            out.append(f"X coordinate changed from {orig_template.x} to {x}.")

        if y:
            # Update y coord
            try:
                y = int(re.sub('[^0-9-]', '', y))
            except ValueError:
                out.append(
                    "Updating y failed, value provided was not a number.")
                await Template.send_end(ctx, out)
                return

            sql.template_kwarg_update(ctx.guild.id,
                                      orig_template.name,
                                      y=y,
                                      date_modified=int(time.time()))
            out.append(f"Y coordinate changed from {orig_template.y} to {y}.")

        if new_name:
            # Check if new name is already in use
            dup_check = sql.template_get_by_name(ctx.guild.id, new_name)
            if dup_check != None:
                out.append(
                    f"Updating name failed, the name {new_name} is already in use."
                )
                await Template.send_end(ctx, out)
                return
            # Check if new name is too long
            if len(new_name) > config.MAX_TEMPLATE_NAME_LENGTH:
                out.append("Updating name failed: " +
                           ctx.s("template.err.name_too_long").format(
                               config.MAX_TEMPLATE_NAME_LENGTH))
                await Template.send_end(ctx, out)
                return
            # Check if new name begins with a '-'
            if new_name[0] == "-":
                out.append(
                    "Updating name failed: Names cannot begin with hyphens.")
                await Template.send_end(ctx, out)
                return
            # Make sure the name isn't a number
            try:
                c = int(new_name)
                out.append("Updating name failed: Names cannot be numbers.")
                await Template.send_end(ctx, out)
                return
            except ValueError:
                pass

            # None with new nick, update template
            sql.template_kwarg_update(ctx.guild.id,
                                      orig_template.name,
                                      new_name=new_name,
                                      date_modified=int(time.time()))
            out.append(f"Nickname changed from {name} to {new_name}.")

        await Template.send_end(ctx, out)
Пример #13
0
async def _quantize(ctx, args, canvas, palette):
    """Sends a message containing a quantised version of the image given.

    Arguments:
    ctx - A commands.Context object.
    args - A list of arguments from the user, all strings.
    canvas - The canvas to use, string.
    palette - The palette to quantise to, a list of rgb tuples.

    Returns:
    The discord.Message object returned when ctx.send() is called to send the quantised image.
    """
    # Argument Parsing
    parser = GlimmerArgumentParser(ctx)
    parser.add_argument("-f", "--faction", default=None, action=FactionAction)
    parser.add_argument("-z", "--zoom", type=int, default=1)

    # Pre-Parsing
    if len(args) == 0:
        name = None
    elif args[0][0] != "-":
        name = args[0]
        args = args[1:]
    else:
        name = None

    try:
        args = vars(parser.parse_args(args))
    except TypeError:
        return

    faction = args["faction"]
    zoom = args["zoom"]

    gid = ctx.guild.id if not faction else faction.id
    t = sql.template_get_by_name(gid, name)

    data = None
    if name:
        if t:
            log.info("(T:{} | GID:{})".format(t.name, t.gid))
            if t.canvas == canvas:
                raise IdempotentActionError
            data = await http.get_template(t.url, t.name)
        else:
            raise TemplateNotFoundError(gid, name)
    else:
        att = await verify_attachment(ctx)
        if att:
            data = io.BytesIO()
            await att.save(data)

    if data:
        template, bad_pixels = await render.quantize(data, palette)

        with io.BytesIO() as bio:
            template.save(bio, format="PNG")
            bio.seek(0)
            f = discord.File(bio, "template.png")
            return await ctx.send(ctx.s("canvas.quantize").format(bad_pixels),
                                  file=f)
Пример #14
0
    async def diff(self, ctx, *args):
        log.info(f"g!diff run in {ctx.guild.name} with args: {args}")

        # Order Parsing
        try:
            name = args[0]
        except TypeError:
            await ctx.send("Error: no arguments were provided.")
            return

        if re.match("-\D+", name) != None:
            name = args[-1]
            args = args[:-1]
        else:
            args = args[1:]

        if re.match("-{0,1}\d+",
                    name) != None:  # Skip to coords + image parsing
            await ctx.invoke_default("diff")
            return

        # Argument Parsing
        parser = GlimmerArgumentParser(ctx)
        parser.add_argument("-e", "--errors", action='store_true')
        parser.add_argument("-s", "--snapshot", action='store_true')
        parser.add_argument("-f",
                            "--faction",
                            default=None,
                            action=FactionAction)
        parser.add_argument("-z", "--zoom", type=int, default=1)
        parser.add_argument("-t", "--excludeTarget", action='store_true')
        colorFilters = parser.add_mutually_exclusive_group()
        colorFilters.add_argument("-ec",
                                  "--excludeColors",
                                  nargs="+",
                                  type=int,
                                  default=None)
        colorFilters.add_argument("-oc",
                                  "--onlyColors",
                                  nargs="+",
                                  type=int,
                                  default=None)
        try:
            a = vars(parser.parse_args(args))
        except TypeError:
            return

        list_pixels = a["errors"]
        create_snapshot = a["snapshot"]
        faction = a["faction"]
        zoom = a["zoom"]
        exclude_target = a["excludeTarget"]
        exclude_colors = a["excludeColors"]
        only_colors = a["onlyColors"]

        gid = ctx.guild.id if not faction else faction.id
        t = sql.template_get_by_name(gid, name)

        if t:
            async with ctx.typing():
                log.info("(T:{} | GID:{})".format(t.name, t.gid))
                data = await http.get_template(t.url, t.name)
                max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
                zoom = max(1, min(zoom, max_zoom))

                fetchers = {
                    'pixelcanvas': render.fetch_pixelcanvas,
                    'pixelzone': render.fetch_pixelzone,
                    'pxlsspace': render.fetch_pxlsspace
                }

                diff_img, tot, err, bad, err_list \
                    = await render.diff(t.x, t.y, data, zoom, fetchers[t.canvas], colors.by_name[t.canvas], create_snapshot)

                done = tot - err
                perc = done / tot
                if perc < 0.00005 and done > 0:
                    perc = ">0.00%"
                elif perc >= 0.99995 and err > 0:
                    perc = "<100.00%"
                else:
                    perc = "{:.2f}%".format(perc * 100)
                out = ctx.s("canvas.diff") if bad == 0 else ctx.s(
                    "canvas.diff_bad_color")
                out = out.format(done, tot, err, perc, bad=bad)

                with io.BytesIO() as bio:
                    diff_img.save(bio, format="PNG")
                    bio.seek(0)
                    f = discord.File(bio, "diff.png")
                    await ctx.send(content=out, file=f)

                if list_pixels and len(err_list) > 0:
                    error_list = []
                    for x, y, current, target in err_list:
                        # Color Filtering
                        c = current if not exclude_target else target
                        if exclude_colors:
                            if c in exclude_colors:
                                continue
                        elif only_colors:
                            if not c in only_colors:
                                continue

                        # The current x,y are in terms of the template area, add to template start coords so they're in terms of canvas
                        x += t.x
                        y += t.y
                        error_list.append(Pixel(current, target, x, y))

                    checker = Checker(self.bot, ctx, t.canvas, error_list)
                    checker.connect_websocket()
        else:
            # No template found
            raise TemplateNotFoundError(gid, name)
Пример #15
0
    async def preview(self, ctx, *args):
        log.info(f"g!preview run in {ctx.guild.name} with args: {args}")

        # Order Parsing
        try:
            name = args[0]
        except TypeError:
            await ctx.send("Error: no arguments were provided.")
            return

        if re.match("-\D+", name) != None:
            name = args[-1]
            args = args[:-1]
        else:
            args = args[1:]

        if re.match("-{0,1}\d+",
                    name) != None:  # Skip to coords + image parsing
            await ctx.invoke_default("preview")
            return

        # Argument Parsing
        parser = GlimmerArgumentParser(ctx)
        parser.add_argument("-t", "--templateRegion", action='store_true')
        parser.add_argument("-f",
                            "--faction",
                            default=None,
                            action=FactionAction)
        parser.add_argument("-z", "--zoom", type=int, default=1)
        try:
            a = vars(parser.parse_args(args))
        except TypeError:
            return

        preview_template_region = a["templateRegion"]
        faction = a["faction"]
        zoom = a["zoom"]

        gid = ctx.guild.id if not faction else faction.id
        t = sql.template_get_by_name(gid, name)

        if t:
            async with ctx.typing():
                log.info("(T:{} | GID:{})".format(t.name, t.gid))
                max_zoom = int(math.sqrt(4000000 // (t.width * t.height)))
                zoom = max(-8, min(zoom, max_zoom))

                fetchers = {
                    'pixelcanvas': render.fetch_pixelcanvas,
                    'pixelzone': render.fetch_pixelzone,
                    'pxlsspace': render.fetch_pxlsspace
                }

                if preview_template_region:
                    preview_img = await render.preview(*t.center(), zoom,
                                                       fetchers[t.canvas])
                else:
                    preview_img = await render.preview_template(
                        t, zoom, fetchers[t.canvas])

                with io.BytesIO() as bio:
                    preview_img.save(bio, format="PNG")
                    bio.seek(0)
                    f = discord.File(bio, "preview.png")
                    await ctx.send(file=f)
                return

        # No template found
        raise TemplateNotFoundError(gid, name)