1. 程式人生 > 程式設計 >Django 實現將圖片轉為Base64,然後使用json傳輸

Django 實現將圖片轉為Base64,然後使用json傳輸

最近使用Django來進行影象的傳輸,由於要求需要使用Json格式進行請求,所以我們嘗試了二進位制編碼放在json裡,發現bytes格式不能打入json,於是轉為了base64

將圖片轉為json

圖片轉為json有2中方法,一個是二進位制後再轉,一個是轉為矩陣以後再轉。

import base64
import cv2

#通過opencv轉base64
img_im= cv2.imread("D://32.png")
aa=base64.b64encode(cv2.imencode('.jpg',img_im)[1]).decode()
print(len(aa)) #17292

#通過bytes再轉base64
bb=base64.b64encode(open("D://32.png",'rb').read())
print(len(bb)) #43848

最後採用了Opencv的方式,主要發現opencv的base64編碼比第二種短一半,所以用了第一種。

客戶端請求傳送資料格式

客戶端請求伺服器的base64,目前我這裡發現2中,通過Postman測試。

第一種 ‘form/data':

#客戶端:
image1= cv2.imread("D://32.png")
aa=base64.b64encode(cv2.imencode('.jpg',image1)[1]).decode()
r = requests.post(url,data={"image": image1})
print(r.content.decode("utf-8"))

#服務端:
def image_base64(request):
 result = request.POST.get("image")
 img_byte = base64.b64decode(result)
 img_np_arr = np.fromstring(img_byte,np.uint8)
 image = cv2.imdecode(img_np_arr,cv2.IMREAD_COLOR)
 #image 已經轉為矩陣了

第二種 ‘application/json':

#客戶端:
image1= cv2.imread("D://32.png")
aa=base64.b64encode(cv2.imencode('.jpg',json={"image": image1})
print(r.content.decode("utf-8"))

#服務端:
def local_ocr_base64(request):
  # result = request.POST.get("image")
  data = request.body  
  data_json=simplejson.loads(data) #data是str格式的,需要轉為json
  result=data_json["image"]
  img_byte = base64.b64decode(result)
  img_np_arr = np.fromstring(img_byte,np.uint8)
  image = cv2.imdecode(img_np_arr,cv2.IMREAD_COLOR)

補充知識:Django將多個圖片儲存成一個URL串返回給前端

說明

Django有ImageField欄位,是封裝好的,使用很方便,但是一個ImageField欄位只能儲存一張圖片的URL,我現在是想將多張圖片儲存在一個欄位裡,然後URL和URL之間用一個自定義的分隔符連線起來,這樣不用為了圖片再設計一個字表。

自定義上傳圖片

設定settings.py檔案,新增如下語句

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media/')
IMAGE_ROOT = os.path.join(MEDIA_ROOT,'images/')
WEB_HOST_MEDIA_URL = os.path.join('http://127.0.0.1:8000',MEDIA_URL[1:],'images/')

MEDIA_ROOT代表的是使用者上傳後的檔案一般儲存的地方,一般在放在專案目錄下,例如BASE_DIR就是取得專案絕對地址。而MEDIA_URL是指URL訪問時的URL。例如,

BASE_DIR: /Users/incisor/VSCodeProjects/python/Notes

那麼

MEDIA_ROOT:/Users/incisor/VSCodeProjects/python/Notes/media

假設media目錄下有一張圖片2019.jpg,那麼

MEDIA_URL: http://127.0.0.1:8000/media/

然後再通過http://127.0.0.1:8000/media/2019.jpg這個URL是可以直接訪問這個圖片的。

IMAGE_ROOT是我自定義的一個欄位,因為我想以後可能會上傳視訊,或者其他一些檔案,想區分開,所以我在media目錄下再建了一個目錄images,那麼

IMAGE_ROOT: /Users/incisor/VSCodeProjects/python/Notes/media/images

WEB_HOST_MEDIA_URL是拼接URL時使用,因為我接下來要自己拼接多個圖的URL,MEDIA_URL[1:]的原因時如果不去掉第一個/,那WEB_HOST_MEDIA_URL會是/media/images/,這顯然不是我們想要的,所以需要把第一個/去掉。

views.py檔案

前端傳過來不定數量的圖片,可能0張,最多9張,每個圖片都做base64編碼再傳過來,POST請求裡有個引數imgs,是一個數組,儲存base64編碼。

base64編碼如下圖所示,這只是一部分:

前面的data:image/png;base64,除了字尾會不同,其他的是固定的,所以我會先從這裡取得字尾png,再做編碼轉換。

import base64
import os
import re
from datetime import date,datetime
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response

from Notes.settings import IMAGE_ROOT,WEB_HOST_MEDIA_URL

@api_view(['POST',])
def images(request):
  urls = ''
  dir_name = date.today().__str__().replace('-','_',2) # 2019_06_21
  dirs = os.path.join(IMAGE_ROOT,dir_name) # 將日期作為目錄名
  if not os.path.isdir(dirs):
    os.makedirs(dirs) # 判斷目錄是否存在,不存在則建立
  for img in request.data['imgs']:
    strs = img.split(',')
    suffix = re.findall(r'/(\w+?);',strs[0])[0] # 取得檔案字尾
    # 拼接伺服器上的檔名
    # datetime.now()取得當前時間,精確到了微秒,一般來說是唯一的了,因為目錄是日期,所以檔名就去掉日期,最後會是一串數字
    img_name = re.sub(r':|\.','',datetime.now().__str__().split(' ')[1]) + '.' + suffix 
    img_path = os.path.join(dirs,img_name)
    with open(img_path,'wb') as out:
      out.write(base64.b64decode(strs[1])) # base64解碼,再寫入檔案
      out.flush()
      urls += os.path.join(WEB_HOST_MEDIA_URL,dir_name,img_name) + '[/--sp--/]' # 拼接URL,URL與URL之間用[/--sp--/]隔開
  result = {}
  result['status'] = status.HTTP_200_OK
  result['message'] = '圖片上傳成功'
  result['urls'] = urls[:len(urls) - len('[/--sp--/]')] # 去掉末尾的[/--sp--/]
  return Response(data=result)

3、urls.py檔案

from django.contrib import admin
from django.urls import path
from django.conf.urls.static import static # 需要新增這句,包含靜態資源之類的
from note import views
from . import settings


urlpatterns = [
  path('notes/images/',views.images),path('admin/',admin.site.urls),]
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) # 這句不設定的話,不能通過URL直接訪問到圖片

4、啟動服務,python3 manage.py runserver

5、POST請求,然後返回對應的JSON資料

{
  "status": 200,"message": "圖片上傳成功","urls": "http://127.0.0.1:8000/media/images/2019_06_21/073249204253.png[/--sp--/]http://127.0.0.1:8000/media/images/2019_06_21/073249854323.png"
}

這樣在資料庫方面,就可以直接用一個varchar型別來儲存多張圖了,前端收到URL串,再按照定好的分隔符[/–sp–/]切開後,就可以顯示了。

以上這篇Django 實現將圖片轉為Base64,然後使用json傳輸就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。