def put_char_vertical(font_size: int, rot: int, cdpt: str, pen_l: Tuple[int, int], canvas_text: np.ndarray, canvas_border: np.ndarray, border_size: int) : pen = pen_l.copy() is_pun = _is_punctuation(cdpt) cdpt, rot_degree = CJK_Compatibility_Forms_translate(cdpt, 1) slot = get_char_glyph(cdpt, font_size, 1) bitmap = slot.bitmap if bitmap.rows * bitmap.width == 0 or len(bitmap.buffer) != bitmap.rows * bitmap.width : char_offset_y = slot.metrics.vertBearingY >> 6 return char_offset_y char_offset_y = slot.metrics.vertAdvance >> 6 bitmap_char = np.array(bitmap.buffer, dtype = np.uint8).reshape((bitmap.rows,bitmap.width)) pen[0] += slot.metrics.vertBearingX >> 6 pen[1] += slot.metrics.vertBearingY >> 6 canvas_text[pen[1]:pen[1]+bitmap.rows, pen[0]:pen[0]+bitmap.width] = bitmap_char #print(pen_l, pen, slot.metrics.vertBearingX >> 6, bitmap.width) #border if border_size > 0 : pen_border = (pen[0] - border_size, pen[1] - border_size) #slot_border = glyph_border = get_char_border(cdpt, font_size, 1) stroker = freetype.Stroker() stroker.set(64 * max(int(0.07 * font_size), 1), freetype.FT_STROKER_LINEJOIN_ROUND, freetype.FT_STROKER_LINEJOIN_ROUND, 0) glyph_border.stroke(stroker, destroy=True) blyph = glyph_border.to_bitmap(freetype.FT_RENDER_MODE_NORMAL, freetype.Vector(0,0), True) bitmap_b = blyph.bitmap bitmap_border = np.array(bitmap_b.buffer, dtype = np.uint8).reshape(bitmap_b.rows,bitmap_b.width) canvas_border[pen_border[1]:pen_border[1]+bitmap_b.rows, pen_border[0]:pen_border[0]+bitmap_b.width] = cv2.add(canvas_border[pen_border[1]:pen_border[1]+bitmap_b.rows, pen_border[0]:pen_border[0]+bitmap_b.width], bitmap_border) return char_offset_y
def _draw_string(cls, img, x_pos, y_pos, cur_pen, cur_char, color): ''' draw string :param x_pos: text x-postion on img :param y_pos: text y-postion on img :param text: text (unicode) :param color: text color :return: image ''' prev_char = 0 pen = freetype.Vector() pen.x = x_pos << 6 # div 64 pen.y = y_pos << 6 image = copy.deepcopy(img) kerning = cls._face.get_kerning(prev_char, cur_char) pen.x += kerning.x slot = cls._face.glyph bitmap = slot.bitmap cur_pen.x = pen.x cur_pen.y = pen.y - slot.bitmap_top * 64 image = cls._draw_ft_bitmap(image, bitmap, cur_pen, color) pen.x += slot.advance.x return image
def _write_glyph(self, glyph): blyph = glyph.to_bitmap(freetype.FT_RENDER_MODE_NORMAL, freetype.Vector(0, 0)) self.char.set_bitmap_geom( (blyph.left, -blyph.top, blyph.bitmap.width, blyph.bitmap.rows)) bitmap = blyph.bitmap return FT2Bitmap(bitmap).to_pil_image()
def draw_string(self, img, x_pos, y_pos, text, color, gap=1): ''' draw string :param x_pos: text x-postion on img :param y_pos: text y-postion on img :param text: text (unicode) :param color: text color :return: image ''' if self.ttf == "data/font/times.ttf": gap = gap * 1.2 elif self.ttf == "data/font/msyhbd.ttf": gap = gap * 1 else: gap = gap prev_char = 0 pen = freetype.Vector() pen.x = x_pos << 6 # div 64 pen.y = y_pos << 6 hscale = 1.0 matrix = freetype.Matrix( int(hscale) * 0x10000, int(0.2 * 0x10000), int(0.0 * 0x10000), int(1.1 * 0x10000)) cur_pen = freetype.Vector() pen_translate = freetype.Vector() image = copy.deepcopy(img) for cur_char in text: self._face.set_transform(matrix, pen_translate) self._face.load_char(cur_char) kerning = self._face.get_kerning(prev_char, cur_char) pen.x += kerning.x slot = self._face.glyph bitmap = slot.bitmap cur_pen.x = pen.x cur_pen.y = pen.y - slot.bitmap_top * 64 self.draw_ft_bitmap(image, bitmap, cur_pen, color) pen.x += int(gap * slot.advance.x) prev_char = cur_char return image
def draw_string(self, img, x_pos, y_pos, text, color, matrix_random=True): ''' draw string :param x_pos: text x-postion on img :param y_pos: text y-postion on img :param text: text (unicode) :param color: text color :return: image ''' prev_char = 0 pen = freetype.Vector() pen.x = x_pos << 6 # div 64 pen.y = y_pos << 6 hscale = 1.0 if matrix_random: h2s = random.uniform(0, 0.4) h4s = random.uniform(1.0, 1.15) matrix = freetype.Matrix(int(hscale)*0x10000, int(h2s*0x10000),\ int(0.0*0x10000), int(h4s*0x10000)) else: matrix = freetype.Matrix(int(hscale)*0x10000, int(0.2*0x10000),\ int(0.0*0x10000), int(1.1*0x10000)) cur_pen = freetype.Vector() pen_translate = freetype.Vector() image = copy.deepcopy(img) for cur_char in text: self._face.set_transform(matrix, pen_translate) self._face.load_char(cur_char) kerning = self._face.get_kerning(prev_char, cur_char) pen.x += kerning.x slot = self._face.glyph bitmap = slot.bitmap cur_pen.x = pen.x cur_pen.y = pen.y - slot.bitmap_top * 64 self.draw_ft_bitmap(image, bitmap, cur_pen, color) pen.x += slot.advance.x prev_char = cur_char return image
def draw_string(self, img, x_pos, y_pos, text, color): ''' draw string :param xpos: text x-position on img :param ypos: text y-position on img :param text: text (unicode) :param color: text color :return: image ''' prev_char = 0 pen = freetype.Vector() pen.x = x_pos << 6 # div 64 pen.y = y_pos << 6 hscale = 1.0 matrix = freetype.Matrix(int((hscale) * 0x10000), int((0.2) * 0x10000), int((0.0) * 0x10000), int((1.1) * 0x10000)) cur_pen = freetype.Vector() pen_translate = freetype.Vector() image = copy.deepcopy(img) for cur_char in text: self._face.set_transform(matrix, pen_translate) self._face.load_char(cur_char) kerning = self._face.get_kerning(prev_char, cur_char) pen.x += kerning.x slot = self._face.glyph bitmap = slot.bitmap cur_pen.x = pen.x cur_pen.y = pen.y - slot.bitmap_top * 64 self.draw_ft_bitmap(image, bitmap, cur_pen, color) pen.x += slot.advance.x prev_char = cur_char return image
def get_glyph(self, stroke=None): glyph = self.face.glyph.get_glyph() if stroke is not None: stroke_width = int(stroke * 64 * self.font.hres / 330) stroker = ft.Stroker() stroker.set(stroke_width, ft.FT_STROKER_LINECAP_ROUND, ft.FT_STROKER_LINEJOIN_ROUND, 0) # StrokeBorder is not wrapped in freetype-py.Glyph... error = ft.FT_Glyph_StrokeBorder(ft.byref(glyph._FT_Glyph), stroker._FT_Stroker, 0, 0) if error: raise ft.FT_Exception(error) blyph = glyph.to_bitmap(ft.FT_RENDER_MODE_NORMAL, ft.Vector(0,0)) blyph.glyph = glyph # keep a reference, otherwise it blows up return blyph
def string_2_bitmap(self, img, x_pos, y_pos, text, color): ''' 将字符串绘制为图片 :param x_pos: text绘制的x起始坐标 :param y_pos: text绘制的y起始坐标 :param text: text的unicode编码 :param color: text的RGB颜色编码 :return: 返回image位图 ''' prev_char = 0 pen = freetype.Vector() pen.x = x_pos << 6 # div 64 pen.y = y_pos << 6 hscale = 1.0 matrix = freetype.Matrix( int(hscale) * 0x10000L, int(0.2 * 0x10000L), int(0.0 * 0x10000L), int(1.1 * 0x10000L)) cur_pen = freetype.Vector() pen_translate = freetype.Vector() image = copy.deepcopy(img) for cur_char in text: self._face.set_transform(matrix, pen_translate) self._face.load_char(cur_char) kerning = self._face.get_kerning(prev_char, cur_char) pen.x += kerning.x slot = self._face.glyph bitmap = slot.bitmap cur_pen.x = pen.x cur_pen.y = pen.y - slot.bitmap_top * 64 self.draw_ft_bitmap(image, bitmap, cur_pen, color) pen.x += slot.advance.x prev_char = cur_char return image
def __fontString(self, img, x_pos, y_pos, text, color, sep=None): prev_char = 0 pen = freetype.Vector() pen.x = x_pos << 6 pen.y = y_pos << 6 cur_pen = freetype.Vector() pen_translate = freetype.Vector() for cur_char in text: # 获取文本图像 if self.__vector == True: self.__face.load_char(cur_char, 6) else: self.__face.load_char( cur_char, freetype.FT_LOAD_MONOCHROME | freetype.FT_LOAD_TARGET_MONO | freetype.FT_LOAD_RENDER) kerning = self.__face.get_kerning(prev_char, cur_char) slot = self.__face.glyph cur_pen.x = pen.x + kerning.x + self.__spc * 64 # 调整字符间距 cur_pen.y = pen.y - slot.bitmap_top * 64 self.__fontImage(img, slot.bitmap, cur_pen, color, sep) pen.x = cur_pen.x + slot.advance.x prev_char = cur_char width, height = self.__font_crop(img) # 图像裁剪和反转 reimage = np.zeros([height, width], np.uint8) for h in range(height): for w in range(width): reimage[h, w] = img[height - h, w] return reimage
def draw_string(self, img, x_pos, y_pos, text, color): """ draw string :param img: ndarray :param x_pos: x coordinate :param y_pos: y coordinate :param text: text(str) :param color: text color :return: image """ prev_char = 0 pen = freetype.Vector() pen.x = x_pos << 6 pen.y = y_pos << 6 hscale = 1.0 matrix = freetype.Matrix( int(hscale) * 0x10000, int(0.2 * 0x10000), int(0.0 * 0x10000), int(1.1 * 0x10000)) cur_pen = freetype.Vector() pen_translate = freetype.Vector() image = copy.deepcopy(img) for cur_char in text: self._face.set_transform(matrix, pen_translate) self._face.load_char(cur_char) # kerning = self._face.get_kerning(prev_char, cur_char) pen.x = pen.x + 170 slot = self._face.glyph bitmap = slot.bitmap cur_pen.x = pen.x cur_pen.y = pen.y - slot.bitmap_top * 64 self.draw_ft_bitmap(image, bitmap, cur_pen, color) # cv2.imshow('image', image) # cv2.waitKey(0) pen.x += slot.advance.x prev_char = cur_char return image
def _set_face_transfrom(self): face = self._font._face horizontal_scale = 100 resolution = self._resolution # dpi face.set_char_size(int(to_64th_point(self._size)), 0, horizontal_scale * resolution, resolution) # Matrix cooeficients are expressed in 16.16 fixed-point units. # 2**16 = 0x10000L = 65536 matrix = freetype.Matrix(2**16 / horizontal_scale, 0, 0, 2**16) # The vector coordinates are expressed in 1/64th of a pixel # (also known as 26.6 fixed-point numbers). delta = freetype.Vector(0, 0) face.set_transform(matrix, delta) freetype.set_lcd_filter(freetype.FT_LCD_FILTER_LIGHT)
def draw_text(self, image, pos, text, text_size, text_color): """ draw chinese(or not) text with ttf :param image: image(numpy.ndarray) to draw text :param pos: where to draw text :param text: the context, for chinese should be unicode type :param text_size: text size :param text_color:text color :return: image """ self._face.set_char_size(text_size * 64) metrics = self._face.size ascender = metrics.ascender / 64.0 ypos = int(ascender) # descender = metrics.descender/64.0 # height = metrics.height/64.0 # linegap = height - ascender + descender x_pos = pos[0] + 2 # pos[0]和pos[1]均为0, y_pos = pos[1] + 8 # + ypos # 加上上行高度, pen = ft.Vector() pen.x = x_pos << 6 # 像素长度x_pos乘以64转化为26.6格式的值 pen.y = y_pos << 6 # hscale = 1.0 # matrix = ft.Matrix(int(hscale) * 0x10000, int(0.2 * 0x10000), int(0.0 * 0x10000), int(1.1 * 0x10000)) # prev_char = 0 # cur_pen = ft.Vector() # pen_translate = ft.Vector() image = np.copy(image) for cur_char in text: # self._face.set_transform(matrix, pen_translate) self._face.load_char(cur_char) # kerning = self._face.get_kerning(prev_char, cur_char) # pen.x += kerning.x # cur_pen.x = pen.x # cur_pen.y = pen.y\ # - self._face.glyph.bitmap_top * 64 # self.draw_ft_bitmap(image, self._face.glyph.bitmap, cur_pen, text_color) self.draw_ft_bitmap(image, self._face.glyph.bitmap, pen, text_color) pen.x += self._face.glyph.advance.x # prev_char = cur_char return image
def draw(font, text, size): print font, text, size face = ft.Face(font) face.set_char_size(size * 64, 0, FREETYPE_DPI, 0) slot = face.glyph #matrix = ft.Matrix() #matrix.xx = (int)( math.cos(0) * 0x10000L) #matrix.xy = (int)(-math.sin(0) * 0x10000L) #matrix.yx = (int)( math.sin(0) * 0x10000L) #matrix.yy = (int)( math.cos(0) * 0x10000L) pen = ft.Vector(0, 0) minx = 0 miny = 0 maxx = 0 maxy = 0 for i, c in enumerate(text): face.set_transform(ft.Matrix(), pen) face.load_char(c, ft.FT_LOAD_RENDER) bitmap = slot.bitmap _l = slot.bitmap_left _t = 0 - slot.bitmap_top minx = min(minx, _l) miny = min(miny, _t) maxx = max(maxx, _l + bitmap.width) maxy = max(maxy, _t + bitmap.rows) pen.x += slot.advance.x pen.y += slot.advance.y width = maxx - minx height = maxy - miny pen.x = (0 - minx) * 64 pen.y = (maxy) * 64 image = Image.new('RGBA', (width, height), (255, 255, 255, 0)) for i, c in enumerate(text): face.set_transform(ft.Matrix(), pen) face.load_char(c, ft.FT_LOAD_RENDER) draw_bitmap(image, slot.bitmap, slot.bitmap_left, height - slot.bitmap_top) pen.x += slot.advance.x pen.y += slot.advance.y return image
def main(stroke=0): """executable entry.""" face = ft.Face('./WenQuanYiMicroHei.ttf') face.set_char_size(48 * 64) if stroke == 0: flags = ft.FT_LOAD_DEFAULT else: flags = ft.FT_LOAD_DEFAULT | ft.FT_LOAD_NO_BITMAP face.load_char('心', flags) slot = face.glyph glyph = slot.get_glyph() if stroke > 0: stroker = ft.Stroker() stroker.set(64, ft.FT_STROKER_LINECAP_ROUND, ft.FT_STROKER_LINEJOIN_ROUND, 0) glyph.stroke(stroker, True) blyph = glyph.to_bitmap(ft.FT_RENDER_MODE_NORMAL, ft.Vector(0, 0), True) bitmap = blyph.bitmap width, rows, pitch = bitmap.width, bitmap.rows, bitmap.pitch print({ 'width': slot.metrics.width >> 6, 'height': slot.metrics.height >> 6, 'horiBearingX': slot.metrics.horiBearingX >> 6, 'horiBearingY': slot.metrics.horiBearingY >> 6, 'horiAdvance': slot.metrics.horiAdvance >> 6, 'bitmapWidth': bitmap.width, 'bitmapHeight': bitmap.rows }) img = Image.new("L", (width, rows), "black") pixels = img.load() for y in range(img.size[1]): offset = y * pitch for x in range(img.size[0]): pixels[x, y] = 255 - bitmap.buffer[offset + x] img.show()
def get_full_binary(self): try: with open(self.cache_file, 'rb') as f: return f.read() except OSError: tex_array = [] for enum, my_char in enumerate(self.face.get_chars()): if self.outline: self.face.load_glyph( my_char[1], freetype.FT_LOAD_FLAGS['FT_LOAD_DEFAULT'] | freetype.FT_LOAD_FLAGS['FT_LOAD_NO_BITMAP']) glyph = self.face.glyph.get_glyph() stroker = freetype.Stroker() stroker.set( int(self.outline_thickness), freetype. FT_STROKER_LINECAPS['FT_STROKER_LINECAP_ROUND'], freetype. FT_STROKER_LINEJOINS['FT_STROKER_LINEJOIN_ROUND'], 0) glyph.stroke(stroker, True) bitmap = glyph.to_bitmap( freetype.FT_RENDER_MODES['FT_RENDER_MODE_NORMAL'], freetype.Vector(0, 0), True).bitmap else: self.face.load_glyph(my_char[1]) bitmap = self.face.glyph.bitmap if enum % MAGIC_NUMBER == 0: for i in range(self.line_height): tex_array.append([]) for j in range(self.line_height * MAGIC_NUMBER): tex_array[-1].append(bytes([0, 0, 0, 0])) start_i = (enum // MAGIC_NUMBER) * self.line_height start_j = (enum % MAGIC_NUMBER) * self.line_height for i in range(bitmap.width): for j in range(bitmap.rows): tex_array[start_i + j][start_j + i] = bytes( 4 * [bitmap.buffer[j * bitmap.width + i]]) full_binary = b''.join(i for row in tex_array for i in row) with open(self.cache_file, 'wb') as f: f.write(full_binary) return full_binary
def draw_text(self, image, pos, text, text_size, color): self.face.set_char_size(text_size * 64) pen = ft.Vector() pen.x = pos[0] pen.y = pos[1] + 10 # img = np.copy(image) # image只是个空的模板,每次返回的是image的含有内容的副本 for cur_char in text: self.face.load_char(cur_char) bitmap = self.face.glyph.bitmap for row in range( bitmap.rows): # 画布矩阵img和bitmap.buffer中的图像都是位于第四象限的图像 for col in range(bitmap.width): # 即上边界为x轴,左边界为y轴 if bitmap.buffer[row * bitmap.width + col] != 0: img[pen.y + row][pen.x + col][0] = color[0] img[pen.y + row][pen.x + col][1] = color[1] img[pen.y + row][pen.x + col][2] = color[2] pen.x += self.face.glyph.advance.x >> 6 # 转化为像素值,每复制完一个字符的像素便向前推进一段距离 # pen.x += 4 # 手动调节字符间距 print(pen.x) return img
def load(self, charcodes=''): ''' Build glyphs corresponding to individual characters in charcodes. Parameters: ----------- charcodes: [str | unicode] Set of characters to be represented ''' face = freetype.Face(self.filename) pen = freetype.Vector(0, 0) hres = 100 * 72 hscale = 1.0 / 100 for charcode in charcodes: face.set_char_size(int(self.size * 64), 0, hres, 72) matrix = freetype.Matrix(int((hscale) * 0x10000), int((0.0) * 0x10000), int( (0.0) * 0x10000), int( (1.0) * 0x10000)) face.set_transform(matrix, pen) if charcode in self.glyphs.keys(): continue # ??? why doesn't the linter find these? flags = freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT flags |= freetype.FT_LOAD_TARGET_LCD face.load_char(charcode, flags) bitmap = face.glyph.bitmap left = face.glyph.bitmap_left top = face.glyph.bitmap_top width = face.glyph.bitmap.width rows = face.glyph.bitmap.rows pitch = face.glyph.bitmap.pitch w = int(width // 3) h = rows # h+1,w+1 to have a black border region = self.atlas.allocate((h + 1, w + 1)) if region is None: print("Cannot store glyph '%c'" % charcode) continue x, y, _, _ = region # sould be y+h+1,x+w+1 but we skip the black border texture = self.atlas[y:y + h, x:x + w] data = [] for i in range(rows): data.extend(bitmap.buffer[i * pitch:i * pitch + width]) data = np.array(data, dtype=np.ubyte).reshape(h, w, 3) texture[...] = data # Build glyph size = w, h offset = left, top advance = face.glyph.advance.x, face.glyph.advance.y u0 = (x + 0.0) / float(self.atlas.shape[0]) v0 = (y + 0.0) / float(self.atlas.shape[1]) u1 = (x + w - 0.0) / float(self.atlas.shape[0]) v1 = (y + h - 0.0) / float(self.atlas.shape[1]) texcoords = (u0, v0, u1, v1) glyph = Glyph(charcode, size, offset, advance, texcoords) self.glyphs[charcode] = glyph # Generate kerning for g in self.glyphs.values(): # 64 * 64 because of 26.6 encoding AND the transform matrix used # in texture_font_load_face (hres = 64) kerning = face.get_kerning(g.charcode, charcode, mode=freetype.FT_KERNING_UNFITTED) if kerning.x != 0: glyph.kerning[g.charcode] = kerning.x / (64.0 * 64.0) kerning = face.get_kerning(charcode, g.charcode, mode=freetype.FT_KERNING_UNFITTED) if kerning.x != 0: g.kerning[charcode] = kerning.x / (64.0 * 64.0)
def create_text(text, font_info, fill=True, stroke=False, stroke_radius=0): face = font_info['font_face'] height = font_info['height'] baseline = font_info['baseline'] height += stroke_radius * 2 slot = face.glyph # First pass to compute bbox width = 0 width2 = 0 previous = 0 for c in text: face.load_char(c) bitmap = slot.bitmap kerning = face.get_kerning(previous, c) width2 = width + bitmap.width + (kerning.x >> 6) width += (slot.advance.x >> 6) + (kerning.x >> 6) previous = c width = max(width, width2) width += 1 width += stroke_radius * 2 Z = np.zeros((height, width), dtype=np.int) # Second pass for actual rendering if fill: x, y = stroke_radius, 0 previous = 0 for c in text: face.load_char(c) bitmap = slot.bitmap top = slot.bitmap_top #left = slot.bitmap_left w, h = bitmap.width, bitmap.rows y = height - baseline - top - stroke_radius kerning = face.get_kerning(previous, c) x += (kerning.x >> 6) #print((c,x,y,w,h)) Z[y:y + h, x:x + w] += np.array(bitmap.buffer, dtype='ubyte').reshape(h, w) x += (slot.advance.x >> 6) previous = c if stroke: x, y = 0, 0 previous = 0 for c in text: face.load_char( c, freetype.FT_LOAD_DEFAULT | freetype.FT_LOAD_NO_BITMAP) slot = face.glyph glyph = slot.get_glyph() stroker = freetype.Stroker() stroker.set(64 * stroke_radius, freetype.FT_STROKER_LINECAP_ROUND, freetype.FT_STROKER_LINEJOIN_ROUND, 0) glyph.stroke(stroker, True) blyph = glyph.to_bitmap(freetype.FT_RENDER_MODE_NORMAL, freetype.Vector(0, 0), True) bitmap = blyph.bitmap #top = slot.bitmap_top #left = slot.bitmap_left #print(blyph.top) top = blyph.top w, h = bitmap.width, bitmap.rows y = height - baseline - top - stroke_radius kerning = face.get_kerning(previous, c) x += (kerning.x >> 6) #print((c,x,y,w,h)) Z[y:y + h, x:x + w] += np.array(bitmap.buffer, dtype='ubyte').reshape(h, w) x += (slot.advance.x >> 6) previous = c Z = np.minimum(Z, 255) return Z