Exemple #1
0
    def add_cells_to_table(self, schema, cell_h, cell_w):
        from generators import Component

        for cell in schema:
            #Color
            if roll() <= self.node.get('cell_p_iscolored'):
                color = (int(roll_value(self.node.get('cell_color'))),)
            else:
                color = None

            #text
            text = 'lautaro ' * 10
            if roll() <= float(self.node.get('text_p_isbold')):
                fontname = self.node.get('font') + ' Bold'
            else:
                fontname =  self.node.get('font')

            #border
            if self.node.get('zero_width') == True:
                border_width = 0
            else:
                border_width = int(roll_value(self.node.get('border_width')))

            img = Component(str(self), (self.width, self.height), self.node, background_color=(255,255,255))
            cell_istance = TableCell(cell_w, cell_h, fontname, self.base_font, self.pad_font_min_size,
                             color = color, text = text, border_width = border_width)

            img = cell_istance.generate(img)
            schema[cell] = img
        return schema
Exemple #2
0
    def put_borders(self, schema):
        """ Take a table schema and fill borders based on params
            N.B. this method works inplace thus modifies the original schema"""
        def add_bs(bs, nodes):
            for node in nodes:
                if node is None:
                    continue
                borders = node['TableCell']['cell_borders']
                for b in bs:
                    if b not in borders:
                        borders.append(b)

        # replicate first cell if row has less cells (title)
        np_schema = np.array(
            [row + [row[0]] * (len(schema[-1]) - len(row)) for row in schema],
            dtype=object)
        first_row = np_schema[
            0, :,
            0]  # create list from first row, every column, first couple element
        first_col = np_schema[:, 0, 0]
        last_row = np_schema[-1, :, 0]
        last_col = np_schema[:, -1, 0]

        # externals
        first_row_borders = ['top']
        if first_row[0]['TableCell'].get(
                'is_title', False
        ) or first_row[0]['TableCell'].get(
                'is_key', False
        ):  # if is title and then no row frame the title must be enclosed
            first_row_borders.append('bottom')

        add_bs(first_row_borders, first_row)
        add_bs(['left'], first_col)
        add_bs(['bottom'], last_row)
        add_bs(['right'], last_col)

        internal_borders = []
        if roll() <= self.row_frame:
            internal_borders.append('bottom')

        if roll() <= self.col_frame:
            internal_borders.append('right')

        add_bs(internal_borders,
               np_schema[:, :, 0].flatten())  # add every cell right border

        return schema
Exemple #3
0
    def get_font(self, text, size):
        width, height = size
        font_name = roll_value(self.f_name)

        font_data = {'name': font_name}
        for style, value in Text.style_map.items():
            if roll() < self.font.get(style, 0):
                font_data.update({style: True})
                font_name += value
        font_name = font_name.replace(' ', '_')
        f_size = roll_value(self.font_size)
        if isinstance(f_size, int):  # check if it fits
            try:
                font = PIL.ImageFont.truetype(font_name, f_size)
            except OSError:
                logging.exception(
                    f"Cannot open font {font_name} with size {f_size}")
                exit(1)
            l_width, l_height = font.getsize(text)
            c_width = l_width / len(text)
            max_chars = width // c_width

            #lines = textwrap.wrap(text, width=int(max_chars))
            if l_height > height or l_width > width:  # doesn't fit, go for filling. N.B. single line!
                f_size = 'fill'  #
                logging.debug(f"Can't fit with font size {f_size}, filling...")

        if f_size == 'fill':
            font_data.update({'filled': True})
            f_size = int(height * 0.8)

            while True:
                try:
                    font = PIL.ImageFont.truetype(font_name, f_size)
                except OSError:
                    logging.exception(
                        f"Cannot open font {font_name} with size {f_size}")
                    exit(1)
                c_width, l_height = font.getsize(text)
                c_width = c_width / len(text)
                max_chars = width // c_width
                if max_chars > 0:
                    #print(f"f_size {f_size}, max_ch {max_chars}")
                    lines = textwrap.wrap(text, width=int(max_chars))
                    if l_height < height and len(lines) == 1:
                        break

                f_size -= 1
        if f_size < self.font_min:
            return None, None
        try:
            font = PIL.ImageFont.truetype(font_name, f_size)
        except OSError:
            logging.exception(
                f"Cannot open font {font_name} with size {f_size}")
            exit(1)
        #logging.debug(f"Using font size {f_size}")
        font_data.update({'size': f_size})

        return font, font_data
Exemple #4
0
    def generate(self, container_size=None, last_w=0, last_h=0):
        """Runs sub-elements generation and computes positions based on the config parameters"""
        size = self.get_size(container_size, last_w, last_h)
        logging.info(f"Generating image with size {size}")

        img = Component(str(self), size,
                        self.node)  # create component with rolled size
        #available_x, available_y = width, height = size
        # total_units = 100
        # unit = (height // total_units)
        last_x2 = last_y2 = 0

        for gen in self.generators:  # iterate over sub_generators

            if roll() > gen.p:
                continue  # skip gen
            try:
                component = gen.generate(size, last_x2,
                                         last_y2)  # generate component
            except Exception as e:
                logging.exception(f"Problems generating {gen} {gen.node}")
                break
            #node = gen.node
            x, y = get_position_range(component, size, last_x2, last_y2)
            x, y = img.check_position_for(x, y, component)

            last_x2 = max(x + component.size[0], last_x2)
            last_y2 = max(y + component.size[1], last_y2)

            # available_x -= x - baseline_x
            # available_y -= y - baseline_y

            img.add(component, (x, y))  # paste generated component
        img.render()
        return img
Exemple #5
0
 def roll_and_run(self, image: Component):
     """Rolls and eventually applies the filter"""
     if roll() <= self.p:
         img = self.run(image)
         for filter in self.exclude:
             image_spoilers = image.node.get('spoilers', dict())
             image_spoilers.get(filter, {
                 'p': 0
             }).update(p=0)  # clear filter probability
         return img
Exemple #6
0
    def generate(self, container_size=None, last_w=0, last_h=0):

        size = self.get_size(container_size, last_w, last_h)

        # spoilers = self.get_spoilers()
        img = Component(str(self),
                        size,
                        self.node,
                        background_color=self.background)

        #n_lines = roll_value(self.n_lines)

        w_border = roll_value(self.node.get('w_border', 0))  # %
        w_border = int(w_border * size[0])
        h_border = roll_value(self.node.get('h_border', 0))
        h_border = int(h_border * size[1])
        width, height = cropped = (size[0] - w_border * 2), (size[1] -
                                                             h_border * 2)

        draw = ImageDraw.Draw(img)
        y = h_border

        text = next(text_gen(self.data_path, self.text))
        if roll() <= self.uppercase:
            text = text.upper()

        font, font_data = self.get_font(text, cropped)
        if font:
            fill = roll_value(self.fill)
            font_data.update({'fill': fill})

            _, l_height = font.getsize('Ag')

            align = roll_value(self.align)
            v_align = roll_value(self.v_align)
            x = w_border
            l_width, _ = draw.textsize(text, font)
            if v_align == 'bottom':
                y = height - l_height
            elif v_align == 'center':
                y = (height - l_height) // 2

            if align == 'right':
                x = width - l_width
            elif align == 'center':
                x = (width - l_width) // 2

            draw.text((x, y), text, font=font, fill=fill, align=align)
            img.annotate({
                'text': text,
                'font': font_data,
                'box': [x, y, l_width, l_height]
            })

        return img
Exemple #7
0
def roll_axis_split(width, height):  # for key value positioning
    """
    Calculating w-h / w+h which belongs to ]-1, 1[ , then normalize in ]0,1[ as p --> w / (w+h)/2

    """
    # augment height to make horizontal split more likely to be rolled (like most table cells)
    height = height + (height * HORIZ_BIAS)
    side_ratio = (width + height) / 2
    p_horizontal = (height / side_ratio)
    if roll() <= p_horizontal:
        return 1
    return 0
Exemple #8
0
    def make_schema(self, table):
        """Create a matrix row x cols with (Cell_node, position)"""
        n_cols = roll_value(self.cols)
        n_rows = roll_value(self.rows)
        if roll() <= self.fix_cols:  # fixed dims
            cell_w = table.width // n_cols
            widths = [cell_w] * n_cols
        else:
            widths = roll_table_sizes(table, n_cols, axis=0)
        if roll() <= self.fix_rows:
            cell_h = table.height // n_rows
            heights = [cell_h] * n_rows
        else:
            heights = roll_table_sizes(table, n_rows, axis=1)

        cell_node = {
            'size': {
                'width': 0,
                'height': 0
            },
            'value': {
                'file': self.values_file,
                'font': self.font
            },
            'key': {
                'p': 0.5,
                'file': self.keys_file,
                'font': self.font
            },
            'cell_borders': [],  # to be filled later on
            'spoilers': self.cell_spoilers
        }
        pos_mapping = list()
        row_idx = col_idx = 0
        if roll() <= self.title:  # create title, one row single cell
            title_node = deepcopy(cell_node)
            h = heights[0]
            del title_node['key']
            title_node['value'].update(file=self.title_file,
                                       font={'size': 'fill'})
            title_node.update(size={
                'width': table.width,
                'height': h
            },
                              is_title=True)
            pos_mapping.append([({
                'TableCell': deepcopy(title_node)
            }, (0, 0))])  # first row
            row_idx = 1

        if roll() <= self.fix_keys_col:  # create keys row

            h = heights[row_idx]
            y = sum(heights[:row_idx])

            key_node = deepcopy(cell_node)
            del key_node['key']

            row = list()
            for j in range(len(widths)):
                x = sum(widths[:j])
                w = widths[j]
                position = x, y
                key_node.update(size={'width': w, 'height': h}, is_key=True)
                key_node['value'].update(file=self.keys_file, uppercase=0.8)
                row.append(({'TableCell': deepcopy(key_node)}, position))
            row_idx += 1
            pos_mapping.append(row)

        # if roll() <= self.fix_keys_row:
        #     w = widths[col_idx]
        #     x = sum(widths[:col_idx]) # 0
        #     key_node = deepcopy(cell_node)
        #     del key_node['key']
        #     col = list()
        #     for i in range(len(heights)):

        while row_idx < len(heights):
            row = []

            for j in range(len(widths)):
                x = sum(widths[:j])
                y = sum(heights[:row_idx])
                w = widths[j]
                h = heights[row_idx]
                position = x, y
                cell_node.update(size={'width': w, 'height': h}, is_val=True)
                row.append(({'TableCell': deepcopy(cell_node)}, position))

            pos_mapping.append(row)
            row_idx += 1

        return pos_mapping
Exemple #9
0
    def populate(self, cell, frame):

        size = cell.size
        # -- white border
        w_border = roll_value(self.w_border)  # in %
        l_border = int(w_border * size[0]) + frame[0]
        r_border = int(w_border * size[0]) + frame[2]
        h_border = roll_value(self.h_border)
        t_border = int(h_border * size[1]) + frame[1]
        b_border = int(h_border * size[1]) + frame[3]
        size = width, height = (size[0] - l_border -
                                r_border), (size[1] - t_border - b_border)

        if roll() <= self.key_p:
            axis_split = roll_axis_split(width,
                                         height)  # 1 for horizontal split
            opposite_ax = abs(axis_split - 1)
            split_size = int(size[axis_split] * roll_value(
                [0.3, 0.7])), size[opposite_ax]  # calc random split on side
            width_key, height_key = split_size[axis_split], split_size[
                opposite_ax]  # permute if axis == 1

            key_node = {
                'Text': {
                    'size': {
                        'width': width_key,
                        'height': height_key
                    },
                    'source_path': self.keys_file,
                    'n_lines': 1,
                    'uppercase': self.key_upper,
                    'font': self.key_font
                }
            }

            key_gen = Text(key_node)
            key = key_gen.generate(container_size=size)
            if key.empty():
                pass
                #return cell
            key.annotate({'value': False, 'key': True, 'axis': axis_split})
            cell.add(key, (l_border, t_border))
            width = size[0] - (width_key * opposite_ax
                               )  # keep side intact or decrement based on axis
            height = size[1] - (height_key * axis_split)
            l_border = (l_border * axis_split) + (
                size[0] - width +
                l_border) * opposite_ax  # calc offset where to place cell
            t_border = (t_border * opposite_ax) + (size[1] - height +
                                                   t_border) * axis_split
        # Creating text generator with calculated size, default alignment and my font info
        value_node = {
            'Text': {
                'size': {
                    'width': width,
                    'height': height
                },
                'source_path': self.values_file,
                'n_lines': 1,
                'background_color': self.background,
                'uppercase': self.value_upper,
                'font': self.value_font
            }
        }

        value_gen = Text(value_node)
        value = value_gen.generate(container_size=size)
        value.annotate({'value': True, 'key': False})
        cell.add(value, (l_border, t_border))
        cell.render()
        return cell
Exemple #10
0
    def generate(self, container_size=None, last_w=0, last_h=0):

        size = self.get_size(container_size, last_w, last_h)

        img = Component(str(self), size, self.node)

        n_lines = roll_value(self.n_lines)

        w_border = roll_value(self.node.get('w_border', 0))  # %
        w_border = int(w_border * size[0])
        h_border = roll_value(self.node.get('h_border', 0))
        h_border = int(h_border * size[1])
        cropped = (size[0] - w_border * 2), (size[1] - h_border * 2)

        font_name = roll_value(self.f_name)
        font_data = {'name': font_name}

        for style, value in TextGroup.style_map.items():
            if roll() < self.font.get(style, 0):
                font_data.update({style: True})
                font_name += value

        font_name = font_name.replace(' ', '_')
        f_size = roll_value(self.font_size)
        try:
            font = PIL.ImageFont.truetype(font_name, f_size)
        except OSError:
            logging.exception(
                f"Cannot open font {font_name} with size {f_size}")
            exit(1)
        width, l_height = font.getsize('Ag')
        while l_height + h_border > cropped[1]:
            f_size -= 1
            font = PIL.ImageFont.truetype(font_name, f_size)
            width, l_height = font.getsize('A g')

        font_data.update({'size': f_size})
        draw = ImageDraw.Draw(img)
        y = h_border
        width = int(cropped[0] // width * 2)
        texts = text_gen(self.data_path)
        fill = roll_value(self.fill)
        font_data.update({'fill': fill})
        x = w_border
        x0, y0 = x, y
        x1 = 0
        text_data = []
        while y + l_height <= cropped[1] and n_lines != 0:

            for line in textwrap.wrap(next(texts), width=width):
                l_width, l_height = font.getsize(line)
                x1 = max(x1, l_width)
                if y + l_height > cropped[1] or n_lines == 0:
                    break
                draw.text((x, y), line, font=font, fill=fill)
                n_lines -= 1
                y += l_height
                text_data.append({
                    'text': line,
                    'font': font_data,
                    'box': [x, y, width, l_height]
                })
        img.annotate({'box': [x0, y0, x1, y], 'text_data': text_data})

        return img
Exemple #11
0
def test2():
    random.seed(14)
    assert student.roll(5, 10) == 30
Exemple #12
0
def test1():
    random.seed(0)
    assert student.roll(2, 6) == 8
Exemple #13
0
def test3():
    random.seed(10)
    assert student.roll(10, 6) == 33