.net 保存base64 图片_教你使用Django Rest Framework解析Base64方式传输的图片

Base64是网络上最常见的用于传输8位字节码的编码方式之一,其原理是基于64个可打印字符来表示二进制数据。

本文将讲述如何使用Django Rest framework框架,处理Base64格式传输的图片文件。

01

Base64介绍

当我们尝试用记事本打开exe、jpg、pdf这些文件时,会看到一堆又一堆的乱码。

这是因为,exe、jpg、pdf这些文件属于二进制文件,文件中是包含很多无法显示和打印的字符的,当我们用记事本打开这些二进制文件时,就需要一个二进制到字符串的转换方法。

Base64就是一种常见的二进制编码方法。

02

Base64原理简介

Base64的原理很简单,首先,准备一个包含64个字符的字符库。

然后,在字符库的基础上对二进制数据进行处理,处理规则如下:每3个字节一组,一共是`3x8=24`bit,划为4组,每组正好6个bit。

这样我们得到4个数字作为每组的索引值,根据索引进行查表,就可以获得表中相应的4个字符,就是编码后的字符串。

所以,使用Base64编码会把3字节的二进制数据编码为4字节的文本数据,虽然数据的长度增加33%,但是可以作为文本数据在邮件正文、网页等直接显示。‍

03

Python中的base64模块

Python中直接内置了base64模块,可以非常方便直接的进行base64的编解码操作:

我们可以看下示例代码:

# 导入base64模块import base64# 创建一个bytes数据byte_data = b'hello world'# 使用base64模块中的b64encode方法进行编码base64_byte = base64.b64encode(byte_data)# 打印编码后的数据print(base64_byte)  # b'aGVsbG8gd29ybGQ='# 使用base64模块中的b64decode方法进行解码print(base64.b64decode(base64_byte))

通过运行这段示例代码,我们可以看到 b'hello world' 被转换成base64字节码b'aGVsbG8gd29ybGQ='

除此之外,base64模块中还提供了urlsafe_b64encode()和urlsafe_b64decode()方法,这些方法是用于生成不包含+和/的字符的字节码的。

因为在URL查询字符串中不支持+号与/,所以urlsafe_b64encode()与urlsafe_b64decode()中会把字符+和/分别变成-和_从而来匹配URL

04

DRF中的base64解析

我们现在来设想一种应用场景,前端将一张图片文件转换成Base64字节码,通过API传递给后端,后端要正常保存该图片的话,是需要将前端传递过来的Base64字节码解码成文件再保存的。

在Django Rest framework (下文简称为DRF)可以这样进行处理。

1.  通过继承ImageField类,自定义一个Base64ImageField类,专门用于对Base64格式的图片文件进行映射

2.  在Base64ImageField类中,重写to_internal_value方法。

代码如下:

def to_internal_value(self, data):    from django.core.files.base import ContentFile    import base64    import six    import uuid    # 检测字段中的内容是否为base64字节码    if isinstance(data, six.string_types):        # 是否包含 data  和 ;base64        if 'data:' in data and ';base64,' in data:            # Break out the header from the base64 content            header, data = data.split(';base64,')        # 对文件进行解码        try:            decoded_file = base64.b64decode(data)        except TypeError:            self.fail('invalid_image')        # 生成随机文件名:        file_name = str(uuid.uuid4())[:12] # 12个字符长度的uuid字符串        # 获取文件后缀名:        file_extension = self.get_file_extension(file_name, decoded_file)        complete_file_name = "%s.%s" % (file_name, file_extension, )        data = ContentFile(decoded_file, name=complete_file_name)    return super(Base64ImageField, self).to_internal_value(data)

to_internal_value方法,用于将前端上传的文件转换成Django框架中的文件对象类型ContentFile,从而能够正常执行框架中的数据保存操作。

我们在重写该方法时,检测下前端上传数据是否符合格式,然后使用Base64模块进行解码即可。

3.  在重写to_internal_value方法时,为了获取前端上传图片的后缀名(文件格式),可以引入python内置的imghdr模块。

imghdr 模块可以推测文件或字节流中的图像的类型,从而获取文件后缀名。

我们将检测图片后缀名的相关代码封装成一个实例方法:get_file_extension,该方法会检测输入文件的类型,并返回输入文件的后缀名。

# 获取文件后缀名的方法def get_file_extension(self, file_name, decoded_file):    # 引入imghdr模块用于检测图片的类型    import imghdr    extension = imghdr.what(file_name, decoded_file)    extension = "jpg" if extension == "jpeg" else extension    return extension

在实际的开发过程中,我们只需要在对应的序列器Serializer中针对上传的图片项使用Base64ImageField这样一个Field类即可。

当数据保存时,对应的序列器会调用save()方法,会依次执行序列器中各个field中的to_internal_value方法,从而实现图片数据的类型转换并保存。

05

完整示例代码

from rest_framework import serializersclass Base64ImageField(serializers.ImageField):    def to_internal_value(self, data):        from django.core.files.base import ContentFile        import base64        import six        import uuid        # 检测字段中的内容是否为base64字节码        if isinstance(data, six.string_types):            # 是否包含 data  和 ;base64            if 'data:' in data and ';base64,' in data:                # Break out the header from the base64 content                header, data = data.split(';base64,')            # 对文件进行解码            try:                decoded_file = base64.b64decode(data)            except TypeError:                self.fail('invalid_image')            # 生成随机文件名:            file_name = str(uuid.uuid4())[:12] # 12个字符长度的uuid字符串            # 获取文件后缀名:            file_extension = self.get_file_extension(file_name, decoded_file)            complete_file_name = "%s.%s" % (file_name, file_extension, )            data = ContentFile(decoded_file, name=complete_file_name)        return super(Base64ImageField, self).to_internal_value(data)    # 获取文件后缀名的方法    def get_file_extension(self, file_name, decoded_file):        # 引入imghdr模块用于检测图片的类型        import imghdr        extension = imghdr.what(file_name, decoded_file)        extension = "jpg" if extension == "jpeg" else extension        return extension
f1b7fda287551a850cec5508acea3daa.gif

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值