def __init__(self, piece_theme: str, size: int = 70): piece_dir = os.path.join('data', 'piece', piece_theme) #: Maps pieces to their corresponding .svg filenames self.pieces_map = { 'r': 'bR', 'q': 'bQ', 'n': 'bN', 'k': 'bK', 'p': 'bP', 'b': 'bB', 'R': 'wR', 'Q': 'wQ', 'N': 'wN', 'K': 'wK', 'P': 'wP', 'B': 'wB' } # Reads the available piece theme's .svg images and save them as .png of appropraite size for piece in self.pieces_map: piece_path = os.path.join(piece_dir, self.pieces_map[piece] + '.svg') image = VipsImage.thumbnail(piece_path, size, height=size) image.write_to_file(f"Images/{ self.pieces_map[piece]}.png") #: Dictionary where pieces are the keys and corresponding PIL Images are the values self.piece_imgs = dict() for piece in self.pieces_map: self.piece_imgs[piece] = Image.open( f"Images/{ self.pieces_map[piece]}.png")
def vips_thumbnail( self, width: int, height: int, **loader_options ) -> VIPSImage: """Get VIPS thumbnail using vips shrink-on-load features.""" filename = self.vips_filename_with_options( str(self.format.path), **loader_options ) image = cached_vips_file(self.format) if image.interpretation in ("grey16", "rgb16"): # Related to https://github.com/libvips/libvips/issues/1941 ? return VIPSImage.thumbnail( filename, width, height=height, size=VIPSSize.FORCE, linear=True ).colourspace(image.interpretation) return VIPSImage.thumbnail( filename, width, height=height, size=VIPSSize.FORCE )
def Render(self): self.render_status = 'starting' self.render_start_time = datetime.datetime.utcnow() p = Popen( [ self.ffmpeg, '-loglevel', 'panic', '-s', '{}x{}'.format(self.output_raster_width, self.output_raster_height), '-pix_fmt', 'yuvj420p', '-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r', str(self.fps), '-i', '-', '-r', str(self.fps), '-f', 'mp4', '-vcodec', 'libx264', '-preset', 'fast', # '-crf', '26', self.output_file_name + '.mp4' ], stdin=PIPE) if self.prores_mez: p_prores = Popen([ self.ffmpeg, '-loglevel', 'panic', '-s', '1920x1080', '-pix_fmt', 'yuvj420p', '-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r', self.fps, '-i', '-', '-r', self.fps, '-f', 'mov', '-vcodec', 'prores', '-profile:v', '3', '-aspect', '16:9', '-y', self.output_file_name + '.mov' ], stdin=PIPE) self.render_status = 'rendering' for frame in range(self.total_frames): gc.collect() begin_scale = 1 diff_increments_zoom = 0 zoom = begin_scale - (diff_increments_zoom * frame) y_total = 0 # at 1 zoom, it's (5184 - 1920) / 79 frames... 41 pixels # at .45 zoom, it's ((5184 *.45) - 1920) / 79 frames... 5 pixels (413/79 total) resize_width = int(self.original_image_width * zoom) resize_height = int(self.original_image_height * zoom) if self.image_lib == 'vips': image_resize = VImage.thumbnail(self.file_path, resize_height) image_resize.copy(xoffset=int(x_total), yoffset=int(y_total)) # output = image_resize.crop(int(x_total), int(y_total), (self.output_raster_width + int(x_total)), (self.output_raster_height + int(y_total))) output = image_resize.crop(0, 0, (self.output_raster_width), (self.output_raster_height)) data = output.write_to_buffer('.JPEG', Q=95) image_bytes = PImage.open(io.BytesIO(data)) image_bytes.save(p.stdin, 'JPEG') image_resize = VImage.thumbnail( self.file_path, (zoom * self.original_image_width)) image_resize.copy(xoffset=int(x_total), yoffset=int(y_total)) output = image_resize.crop(0, 0, self.output_raster_width, self.output_raster_height) data = output.write_to_buffer('.JPEG', Q=95) image_bytes = PImage.open(io.BytesIO(data)) image_bytes.save(p.stdin, 'JPEG') if self.image_lib == 'pillow': image_resize = self.original_image.resize( (resize_width, resize_height), resample=PImage.BICUBIC) image_offset = PImageChops.offset(image_resize, xoffset=int(0), yoffset=int(y_total)) image = image_offset.crop((0, 0, self.output_raster_width, self.output_raster_height)) image.save(p.stdin, 'JPEG') # image.save(p_prores.stdin, 'JPEG') if self.image_lib == 'cv': _top = (self.output_raster_height - self.original_image_height) _left = (self.output_raster_width - self.original_image_width) top = int(_top / 2) bottom = _top - top left = int(_left / 2) right = _left - left color = [255, 255, 255] constant = cv2.copyMakeBorder(self.original_image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) from_pil = PImage.fromarray(constant) from_pil.save(p.stdin, 'JPEG') # from_pil.show() if self.prores_mez: from_pil.save(p_prores.stdin, 'JPEG') self.render_status_update() # https://stackoverflow.com/questions/13294919/can-you-stream-images-to-ffmpeg-to-construct-a-video-instead-of-saving-them-t # For anyone who stumbles upon this in the future, replacing 'mjpeg' with 'png' and 'JPEG' with 'PNG' worked for me to use png. # python 3.6 https://stackoverflow.com/questions/40108816/python-running-as-windows-service-oserror-winerror-6-the-handle-is-invalid p.stdin.close() p.wait() gc.collect() self.time_end = datetime.datetime.utcnow() seconds_delta = (self.time_end - self.render_start_time).total_seconds() print('Render Complete. {} minutes'.format(seconds_delta / 60)) self.render_status = 'done'