banner
月落星河Tsukistar

月落星河Tsukistar

浩瀚中的伟大,孤独间的渺小
github
twitter
youtube
bilibili
email

在serverless环境下动态调整图像大小的系统的设计与实现

最近畢業設計選題,基於我之前做過的項目和圖像處理有關,serverless 也是最近幾年開始流行的一種服務,於是選擇這個題目,從零開始研究 serverless。(後記:出題老師後來想了想我這個的工作量太小了,所以把題目擴充了許多,現在要去研究證件識別和處理之類的了 QwQ)

參考文章:【AWS 徵文】使用 AWS Serverless 架構動態調整圖片大小

開發環境#

Python 3.6(腾讯云對於 Python 3 目前只支持這個版本),腾讯云 SCF

步驟#

配置環境#

在腾讯云的 “Serverless Framework” 中新建一個 Flask 框架,名稱和地區隨便填,如下圖:

新建框架

部署完成後在 “開發部署” 中點擊 “更新代碼”:

更新代碼

隨後選擇本地開發將項目下載下來:

下載代碼

(其實更便捷的地方在 “雲函數 - 函數服務 - 選擇新建的那個函數 - 函數代碼” 處修改代碼或者新增文件,可以保證環境的一致性,但是上面的方法便於本機調試與修改,各有利弊)

雲函數在線修改

至此,基本框架已經搭好了。

功能開發#

目前函數能夠處理並返回的圖片存放於我的雲存儲,主要是便於調用和預留參數。利用 Flask app 的固有格式,預留了 screen_width(屏幕寬度)和 pic_url(圖片路徑)兩個參數。
在調用時,指定屏幕寬度則返回對應寬度等比縮放的圖片:

等比縮放

不指定則返回原圖:

原圖

在 Flask 部分代碼如下:

@app.route("/pic/<pic_url>")
def source_picture(pic_url):
    img_src = "存儲空間地址" + pic_url
    # 相當於把一張圖片讀入再讀出,圖片大小會變得小一些
    response = make_response(picture.image_output(picture.image_input(img_src)))
    # 設置response的headers對象
    response.headers['Content-Type'] = 'image/jpeg'
    return response


@app.route("/pic/<screen_width>/<pic_url>")
def picture_url_get(screen_width, pic_url):
    # 避免數據類型錯誤
    width = int(screen_width)
    img_src = "存儲空間地址" + pic_url
    # 創建response對象
    response = make_response(picture.image_output(picture.image_resize(width, img_src)))
    # 設置response的headers對象
    response.headers['Content-Type'] = 'image/jpeg'
    return response

主要使用了 make_response 來創建 response 對象包裝圖片,並返回到瀏覽器,避免先存儲再訪問存儲好的圖片。

對於圖片處理部分:

image_input 函數使用 requests 從 URL 獲取圖片,封裝成 response 對象,隨後用 PIL 的 Image 庫打開,注意 response 對象要用 BytesIO 處理:

def image_input(img_src):
    response = requests.get(img_src, headers=headers)
    image = Image.open(BytesIO(response.content))
    return image

image_output 函數使用 BytesIO 將圖片轉換為字節流,保存後返回:

def image_output(image):
    img_byte = BytesIO()
    image.save(img_byte, format="JPEG")
    img_byte = img_byte.getvalue()
    return img_byte

image_resize 函數使用了 Image 裡的 resize 方法,將圖片進行等比縮放,其中 Image.ANTIALIAS 是高清晰度的參數:

def image_resize(width, img_src):
    image = image_input(img_src)
    resize = image.resize((width, int(image.size[1] * width / image.size[0])), Image.ANTIALIAS)
    return resize

遇到的問題與解決方案#

npm 安裝時遇到 rollbackFailedOptional: verb npm-session 問題#

使用npm install -g cnpm --registry=https://registry.npm.taobao.org命令,用淘寶源替換官方源,隨後使用 cnpm 進行安裝。

安裝相應第三方庫報錯#

可以使用阿里鏡像:https://mirrors.aliyun.com/pypi/simple/ ,同時serverless.yml文件中 pip 的相關代碼改為hook: pip install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt -t ./

Pillow 的 import 錯誤#

原因為本地環境與雲端環境不一致,即使均為 Python 3.6.0 版本,Windows 上與 Linux 上的第三方庫也有細微的不同。解決方法為將代碼上傳後,在雲端執行pip install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt -t ./下載依賴。

總結#

整個流程下來自己大致摸清了部署 serverless 服務的步驟,同時也意識到由於 serverless 的依賴都是隨著代碼附帶的,若開發和部署不是同一個操作系統,建議在代碼上傳後於雲環境中進行部署,以免發生運行時的錯誤。

圖片大小的改變只是其中的一個小應用,理論上來講許多應用都可以在 serverless 環境下運行並得出結果,例如短鏈接、圖像識別、文字識別等等,未來 serverless 的應用會愈發廣泛。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。