def crop_image(image: Image.Image, x: int, y: int, w: int, h: int) -> Image.Image: logger.debug( '图片裁剪:裁剪图片 {image},' '裁剪区域 x:{x}+{w} y:{y}+{h}'.format(image=image, x=x, y=y, w=w, h=h)) image = image.crop((x, y, x + w, y + h)) logger.debug('图片裁剪:完成√') return image
def resize_image(image: Image.Image, max_width: int, max_height: int) -> Image.Image: logger.debug('图片缩放:缩放图片 {image},' '目标尺寸 {width} * {height}'.format(image=image, width=max_width, height=max_height)) w, h = image.size if w > max_width or h > max_height: ratio = min(max_width / w, max_height / h) image = image.resize((int(w * ratio), int(h * ratio)), Image.ANTIALIAS) logger.debug('图片缩放:完成√') return image
def generate_thumbnails(image: Image, sizes: dict, target_format: str = 'PNG', target_mode: str = 'RGBA', optimize: bool = False) -> dict: thumbs = {} for size, limits in sizes.items(): logger.debug('缩略图生成:生成缩略图 {size} {limits}'.format(size=size, limits=limits)) resized_image = resize_image(image, limits['WIDTH'], limits['HEIGHT']) compressed_io = compress_image(resized_image, limits['SIZE'], target_format, target_mode, optimize) thumbs[size] = compressed_io logger.debug('缩略图生成:完成√') return thumbs
def url(self, name, virtual_name: str = None, sign: bool = True): name = self._get_target_name(name) logger.debug('OSS存储后端:生成url {path},签名:{sign}'.format(path=name, sign=sign)) params = dict() if not virtual_name: virtual_name = name params.update(_make_content_headers(virtual_name)) if sign: return self.bucket.sign_url( 'GET', name, OSS_SIGNED_URL_EXPIRE, params=params) # default access link expire time: 5min else: return self.bucket._make_url(self.bucket_name, name)
def listdir(self, name): name = self._get_target_name(name) logger.debug('OSS存储后端:列目录 {path}'.format(path=name)) if name and name.endswith('/'): name = name[:-1] files = [] dirs = set() for obj in ObjectIterator(self.bucket, prefix=name, delimiter='/'): if obj.is_prefix(): dirs.add(obj.key) else: files.append(obj.key) return list(dirs), files
def get_preferred_language(cls, request): try: lang_codes = request.headers['Accept-Language'].split(';') lang_codes = [x.split(',') for x in lang_codes] accept_langs = set() accept_langs.add(cls.LANGUAGE_CODE_MAPPING[lang_codes[0][0]]) for lang in lang_codes[1:]: try: accept_langs.add(cls.LANGUAGE_CODE_MAPPING[lang[1]]) except KeyError: pass for lang in accept_langs: if lang in settings.LANGUAGES: return lang except Exception: pass # 忽略处理过程中的所有错误,并返回网站默认语言 logger.debug('语言中间件:读取Accept-Language发生错误,返回系统默认语言') return settings.LANGUAGE_CODE
def compress_image(image: Image.Image, target_size: int, target_format: str = 'PNG', target_mode: str = 'RGBA', optimize: bool = False) -> BytesIO: image = image.convert(mode=target_mode) temp_io = BytesIO() image.save(temp_io, target_format, optimize=optimize) w, h = image.size ratio = 1 logger.debug( '图片压缩:压缩图片 {image}({size}),目标大小 {target_size},' '目标格式 {target_format}'.format(image=image, size=temp_io.tell(), target_size=target_size, target_format=target_format)) while temp_io.tell() > target_size: ratio -= 0.1 if ratio <= 0: raise Exception(_('图片压缩失败!')) resized_image = image.resize(w * ratio, h * ratio) temp_io = BytesIO() resized_image.save(temp_io, target_format, optimize=optimize) logger.debug('图片压缩:完成√') return temp_io
def __call__(self, request): logger.debug('语言中间件:收到请求,开始处理。') user = request.user if user.is_authenticated: profile = user.profile lang = profile.language logger.debug('语言中间件:成功获取到UserProfile') translation.activate(lang) response = self.get_response(request) response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang) elif settings.LANGUAGE_COOKIE_NAME in request.COOKIES: logger.debug('语言中间件:用户未登录,读取COOKIE') lang = request.COOKIES[settings.LANGUAGE_COOKIE_NAME] if lang in settings.LANGUAGES: translation.activate(lang) response = self.get_response(request) else: logger.debug('语言中间件:用户未登录,读取Accept-Language请求头') lang = self.get_preferred_language(request) translation.activate(lang) response = self.get_response(request) response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang) logger.debug('语言中间件:语言已设定为 %s' % lang) return response
def _save(self, name, content: File): # 为保证django行为的一致性,保存文件时,应该返回相对于`media path`的相对路径。 target_name = self._get_target_name(name) logger.debug('OSS存储后端:保存文件 %s' % target_name) content.open() # 默认分片大小 1MB DEFAULT_CHUNK_SIZE = 1 * 1024 * 1024 logger.debug('OSS存储后端:读取完成,文件大小 %d' % content.size) if not content.multiple_chunks(chunk_size=DEFAULT_CHUNK_SIZE): logger.debug('OSS存储后端:不分片,开始上传') # 不分片 content_str = content.file.read() self.bucket.put_object(target_name, content_str) else: logger.debug('OSS存储后端:分片,开始上传') # 改用分片上传方式 upload_id = self.bucket.init_multipart_upload( target_name).upload_id parts = [] part_id = 1 for chunk in content.chunks(chunk_size=DEFAULT_CHUNK_SIZE): # TODO Create an API endpoint for getting uploading process result = self.bucket.upload_part(target_name, upload_id, part_id, chunk) parts.append(PartInfo(part_id, result.etag)) part_id += 1 logger.debug('OSS存储后端:上传分片 #%d' % part_id) result = self.bucket.complete_multipart_upload( target_name, upload_id, parts) logger.debug('OSS存储后端:上传完毕,关闭文件') content.close() return self._clean_name(name)
def _open(self, name, mode='rb'): name = self._get_target_name(name) logger.debug('OSS存储后端:打开文件 {name},模式 {mode}'.format(name=name, mode=mode)) file = AliyunFile(name, self, mode) return file