def draw(self, frame, text, x, y, color=0xf, composite_op="copy", tracking=1): """Uses this font's characters to draw the given string at the given position.""" for ch in text: ch, char_x, char_y, width, left = self.char_metrics(ch) Frame.copy_rect(dst=frame, dst_x=x, dst_y=y + self.margin_top, src=self.bitmaps[color], src_x=char_x + left, src_y=char_y + self.top, width=width, height=self.char_size - self.top - self.bottom + self.margin_top, op=composite_op) x += width + tracking return x
def __draw_frame(self, y, anim, draw): if(self.animation_library is None): return y src = self.animation_library[anim].frames[0] if draw: Frame.copy_rect(dst=self.frame, dst_x=0, dst_y=y, src=src, src_x=0, src_y=0, width=self.frame.width, height=src.height) y+=src.height return y
def __draw_frame(self, y, anim, draw): if(self.game is None): return y if(anim not in self.game.animations): return y src = self.game.animations[anim].frames[0] if draw: Frame.copy_rect(dst=self.frame, dst_x=0, dst_y=y, src=src, src_x=0, src_y=0, width=self.frame.width, height=src.height) y+=src.height return y
def draw(self, frame, text, x, y): """Uses this font's characters to draw the given string at the given position.""" for ch in text: char_offset = ord(ch) - ord(' ') if char_offset < 0 or char_offset >= 96: continue char_x = self.char_size * (char_offset % 10) char_y = self.char_size * (char_offset / 10) width = self.char_widths[char_offset] Frame.copy_rect(dst=frame, dst_x=x, dst_y=y, src=self.bitmap, src_x=char_x, src_y=char_y, width=width, height=self.char_size, op=self.composite_op) x += width + self.tracking return x
def populate_from_dmd_file(self, f): f.seek(0, os.SEEK_END) # Go to the end of the file to get its length file_length = f.tell() f.seek(4) # Skip over the 4 byte DMD header. frame_count = struct.unpack("I", f.read(4))[0] self.width = struct.unpack("I", f.read(4))[0] self.height = struct.unpack("I", f.read(4))[0] if file_length != 16 + self.width * self.height * frame_count: raise ValueError, "File size inconsistent with header information. Old or incompatible file format?" for frame_index in range(frame_count): str_frame = f.read(self.width * self.height) new_frame = Frame(self.width, self.height) new_frame.set_data(str_frame) self.frames.append(new_frame)
def convertImageToOldDMD(src): pal_image= Image.new("P", (1,1)) tuplePal = VgaDMD.get_palette() flatPal = [element for tupl in tuplePal for element in tupl] pal_image.putpalette(flatPal) src_rgb = src.convert("RGB").quantize(palette=pal_image) src_p = src_rgb.convert("P") (w,h) = src.size frame = Frame(w, h) for x in range(w): for y in range(h): color = src_p.getpixel((x,y)) frame.set_dot(x=x, y=y, value=color) return frame
def load(self, filename): """Loads the font from a ``.dmd`` file (see :meth:`Animation.load`). Fonts are stored in .dmd files with frame 0 containing the bitmap data and frame 1 containing the character widths. 96 characters (32..127, ASCII printables) are stored in a 10x10 grid, starting with space (``' '``) in the upper left at 0, 0. The character widths are stored in the second frame within the 'raw' bitmap data in bytes 0-95. """ self.__anim.load(filename) if self.__anim.width != self.__anim.height: raise ValueError, "Width != height!" if len(self.__anim.frames) == 1: # We allow 1 frame for handmade fonts. # This is so that they can be loaded as a basic bitmap, have their char widths modified, and then be saved. print "Font animation file %s has 1 frame; adding one" % (filename) self.__anim.frames += [ Frame(self.__anim.width, self.__anim.height) ] elif len(self.__anim.frames) != 2: raise ValueError, "Expected 2 frames: %d" % (len( self.__anim.frames)) self.char_size = self.__anim.width / 10 self.bitmap = self.__anim.frames[0] self.char_widths = [] for i in range(96): self.char_widths += [ self.__anim.frames[1].get_dot(i % self.__anim.width, i / self.__anim.width) ] return self
def frame_for_markup(self, markup, y_offset=0): """Returns a Frame with the given markup rendered within it. The frame width is fixed, but the height will be adjusted to fit the contents while respecting min_height. The Y offset can be configured supplying *y_offset*. """ lines = markup.split('\n') for draw in [False, True]: y = y_offset for line in lines: if line.startswith("{") and line.endswith('}'): # frame!! y = self.__draw_frame(y=y, anim=line[1:-1], draw=draw) elif line.startswith('#') and line.endswith('#'): # centered headline! y = self.__draw_text(y=y, text=line[1:-1], font=self.font_bold, justify='center', draw=draw) elif line.startswith('#'): # left-justified headline y = self.__draw_text(y=y, text=line[1:], font=self.font_bold, justify='left', draw=draw) elif line.endswith('#'): # right-justified headline y = self.__draw_text(y=y, text=line[:-1], font=self.font_bold, justify='right', draw=draw) elif line.startswith('[') and line.endswith(']'): # centered text y = self.__draw_text(y=y, text=line[1:-1], font=self.font_plain, justify='center', draw=draw) elif line.endswith(']'): # right-justified text y = self.__draw_text(y=y, text=line[:-1], font=self.font_plain, justify='right', draw=draw) elif line.startswith('['): # left-justified text y = self.__draw_text(y=y, text=line[1:], font=self.font_plain, justify='left', draw=draw) else: # left-justified but nothing to clip off y = self.__draw_text(y=y, text=line, font=self.font_plain, justify='left', draw=draw) if not draw: # this was a test run to get the height self.frame = Frame(width=self.width, height=max(self.min_height, y)) return self.frame
def convertImage(src): image = src.convert("RGB") (w,h) = image.size frame = Frame(w, h) mode = image.mode size = image.size data = image.tostring() #assert mode in 'RGB', 'RGBA' surface = pygame.image.fromstring(data, size, mode) frame.set_surface(surface) return frame
def make_colors(self,colors): for c in colors: ##print "Making " + str(c) frame = Frame(self.__anim.width,self.__anim.height) for y in range(self.__anim.height): for x in range(self.__anim.width): dot = self.bitmaps[0].get_dot(x,y) if dot > 1: newdot = ((c << 4) | (dot & 0xF)) frame.set_dot(x, y, newdot) elif dot == 1: newdot = dot frame.set_dot(x,y, newdot) else: pass self.bitmaps[c] = frame
def save(self, filename): """Save the font to the given path.""" out = Animation() out.width = self.__anim.width out.height = self.__anim.height out.frames = [self.bitmap, Frame(out.width, out.height)] for i in range(96): out.frames[1].set_dot(i%self.__anim.width, i/self.__anim.width, self.char_widths[i]) out.save(filename)
def populate_from_image_file(self, path, f): if not Image: raise RuntimeError, 'Cannot open non-native image types without Python Imaging Library: %s' % ( path) src = Image.open(f) (w, h) = src.size if len(self.frames) > 0 and (w != self.width or h != self.height): raise ValueError, "Image sizes must be uniform! Anim is %dx%d, image is %dx%d" % ( w, h, self.width, self.height) (self.width, self.height) = (w, h) if path.endswith('.gif'): from . import animgif self.frames += animgif.gif_frames(src) else: alpha = None try: alpha = Image.fromstring('L', src.size, src.tostring('raw', 'A')) except: pass # No alpha channel available? reduced = src.convert("L") frame = Frame(w, h) # Construct a lookup table from 0-255 to 0-15: eight_to_four_map = [0] * 256 for l in range(256): eight_to_four_map[l] = int(round((l / 255.0) * 15.0)) for x in range(w): for y in range(h): color = eight_to_four_map[reduced.getpixel((x, y))] if alpha: color += eight_to_four_map[alpha.getpixel((x, y))] << 4 frame.set_dot(x=x, y=y, value=color) self.frames.append(frame)
def drawHD(self, frame, text, x, y, line_color, line_width, interior_color, fill_color): """Uses this font's characters to draw the given string at the given position.""" #t = self.pygFont.render(text,False,(255,0,255),(0,0,0)) #surf = self.pygFont.render(text,False,self.color,(0,0,0)) if(text == ""): return x if(fill_color==None): fill_color=(0,0,0) surf = self.textHollow(text,line_color, interior_color, 2*line_width, fill_color) (w,h) = surf.get_size() tmp = Frame(w,h) tmp.pySurface = surf Frame.copy_rect(dst=frame, dst_x=x, dst_y=y, src=tmp, src_x=0, src_y=0, width=w, height=h, op=self.composite_op) #Frame.copy_rect(dst=frame, dst_x=x, dst_y=y, src=self.bitmap, src_x=char_x, src_y=char_y, width=width, height=self.char_size, op=self.composite_op) return x
def populate_from_image_file(self, path, f): if not Image: raise RuntimeError, 'Cannot open non-native image types without Python Imaging Library: %s' % (path) src = Image.open(f) (w, h) = src.size if len(self.frames) > 0 and (w != anim.width or h != anim.height): raise ValueError, "Image sizes must be uniform! Anim is %dx%d, image is %dx%d" % (w, h, self.width, self.height) (self.width, self.height) = (w, h) if path.endswith('.gif'): from . import animgif self.frames += animgif.gif_frames(src) else: alpha = None try: alpha = Image.fromstring('L', src.size, src.tostring('raw', 'A')) except: pass # No alpha channel available? reduced = src.convert("L") frame = Frame(w, h) # Construct a lookup table from 0-255 to 0-15: eight_to_four_map = [0] * 256 for l in range(256): eight_to_four_map[l] = int(round((l/255.0) * 15.0)) for x in range(w): for y in range(h): color = eight_to_four_map[reduced.getpixel((x,y))] if alpha: color += eight_to_four_map[alpha.getpixel((x,y))] << 4 frame.set_dot(x=x, y=y, value=color) self.frames.append(frame)
def draw(self, frame, text, x, y, color = None): """Uses this font's characters to draw the given string at the given position.""" #t = self.pygFont.render(text,False,(255,0,255),(0,0,0)) if(color is None): color=(255,255,255) surf = self.pygFont.render(text,False,color,(0,0,0)) (w,h) = surf.get_size() #surf = pygame.surface.Surface((w, h)) #surf.blit(t,(0,0)) #surf.blit(t2,(2,2)) tmp = Frame(w,h) tmp.pySurface = surf tmp.composite_op = "blacksrc" Frame.copy_rect(dst=frame, dst_x=x, dst_y=y, src=tmp, src_x=0, src_y=0, width=w, height=h, op=self.composite_op) #Frame.copy_rect(dst=frame, dst_x=x, dst_y=y, src=self.bitmap, src_x=char_x, src_y=char_y, width=width, height=self.char_size, op=self.composite_op) return x
def populate_from_dmd_file(self, f): f.seek(0, os.SEEK_END) # Go to the end of the file to get its length file_length = f.tell() ## MJO: Don't just skip the header! Check it. f.seek(0) # Skip over the 4 byte DMD header. dmd_version = struct.unpack("I", f.read(4))[0] dmd_style = 0 # old if(dmd_version == 0x00646D64): # print("old dmd style") pass elif(dmd_version == 0x00DEFACE): # print("full color dmd style") dmd_style = 1 frame_count = struct.unpack("I", f.read(4))[0] self.width = struct.unpack("I", f.read(4))[0] self.height = struct.unpack("I", f.read(4))[0] if(dmd_style==0): if file_length != 16 + self.width * self.height * frame_count: logging.getLogger('game.dmdcache').warning(f) logging.getLogger('game.dmdcache').warning("expected size = {%d} got {%d}", (16 + self.width * self.height * frame_count), (file_length)) raise ValueError, "File size inconsistent with original DMD format header information. Old or incompatible file format?" elif(dmd_style==1): if file_length != 16 + self.width * self.height * frame_count * 3: logging.getLogger('game.dmdcache').warning(f) raise ValueError, "File size inconsistent with true-color DMD format header information. Old or incompatible file format?" for frame_index in range(frame_count): new_frame = Frame(self.width, self.height) if(dmd_style==0): str_frame = f.read(self.width * self.height) new_frame.build_surface_from_8bit_dmd_string(str_frame) elif(dmd_style==1): str_frame = f.read(self.width * self.height * 3) surface = pygame.image.fromstring(str_frame, (self.width, self.height), 'RGB') new_frame.set_surface(surface) self.frames.append(new_frame)
def load(self, filename): """Loads the font from a ``.dmd`` file (see :meth:`Animation.load`). Fonts are stored in .dmd files with frame 0 containing the bitmap data and frame 1 containing the character widths. 96 characters (32..127, ASCII printables) are stored in a 10x10 grid, starting with space (``' '``) in the upper left at 0, 0. The character widths are stored in the second frame within the 'raw' bitmap data in bytes 0-95. """ self.__anim.load(filename) if self.__anim.width != self.__anim.height: raise ValueError, "Width != height!" root, ext = os.path.splitext(filename) metrics_filename = root + ".metrics.json" self.metrics = None left = 0 if os.path.exists(metrics_filename): with open(metrics_filename) as fp: self.metrics = json.load(fp) left = self.metrics.get("left", 0) self.top = self.metrics.get("top", 0) self.margin_top = self.metrics.get("margin_top", 0) self.bottom = self.metrics.get("bottom", 0) elif len(self.__anim.frames) == 1: # We allow 1 frame for handmade fonts. # This is so that they can be loaded as a basic bitmap, have their char widths modified, and then be saved. print "Font animation file %s has 1 frame; adding one" % (filename) self.__anim.frames += [Frame(self.__anim.width, self.__anim.height)] elif len(self.__anim.frames) != 2: raise ValueError, "Expected 2 frames: %d" % (len(self.__anim.frames)) self.char_size = self.__anim.width / 10 self.bitmap = self.__anim.frames[0] # FIXME: Create a separate bitmap for each possible color. This makes # rendering fast, but could be improved self.bitmaps = {} self.bitmaps[0xf] = self.bitmap for color in xrange(1, 0xf): #print color width = self.bitmap.width height = self.bitmap.height self.bitmaps[color] = Frame(width, height) bitmap = self.bitmaps[color] fill = Frame(width, height) sub_color = 0xf - color fill.fill_rect(0, 0, width, height, sub_color) Frame.copy_rect(bitmap, 0, 0, self.bitmap, 0, 0, width, height) Frame.copy_rect(bitmap, 0, 0, fill, 0, 0, width, height, "sub") """ for x in xrange(self.bitmap.width): for y in xrange(self.bitmap.height): dot = self.bitmap.get_dot(x, y) - (0xf - color) if dot > 0: self.bitmaps[color].set_dot(x, y, dot) """ self.char_widths = [] self.left = [] if not self.metrics: for i in xrange(95): self.char_widths += [self.__anim.frames[1].get_dot(i%self.__anim.width, i/self.__anim.width)] self.left += [0] else: overrides = self.metrics.get("left_override", {}) for i in xrange(95): self.char_widths += [self.metrics["widths"][i][1]] ch = chr(ord(' ') + i) self.left += [overrides.get(ch, left)] return self