diff --git a/pics_server/main.py b/pics_server/main.py index b5223fb..1e8dc66 100644 --- a/pics_server/main.py +++ b/pics_server/main.py @@ -1,7 +1,7 @@ import uvicorn from fastapi import Depends, FastAPI -from .routers import pics +from .routers import image # from . import models from .sql.database import engine, Base @@ -14,7 +14,7 @@ Base.metadata.create_all(bind=engine) app = FastAPI() -app.include_router(pics.router) +app.include_router(image.router) # app.mount("/static", StaticFiles(directory="static"), name="static") diff --git a/pics_server/models/image.py b/pics_server/models/image.py index fdb628b..291ce4b 100644 --- a/pics_server/models/image.py +++ b/pics_server/models/image.py @@ -1,3 +1,4 @@ +from turtle import heading, width from sqlalchemy import Column, Integer, String # from sqlalchemy.orm import relationship @@ -9,4 +10,7 @@ class Image(Base): id = Column(Integer, primary_key=True, index=True) file_path = Column(String, unique=True) file_name = Column(String) - upload_time = Column(String) + upload_time = Column(Integer) + size = Column(Integer) + width = Column(Integer) + height = Column(Integer) diff --git a/pics_server/routers/image.py b/pics_server/routers/image.py index e69de29..2e776ee 100644 --- a/pics_server/routers/image.py +++ b/pics_server/routers/image.py @@ -0,0 +1,110 @@ +from copy import deepcopy +import mimetypes +from io import BytesIO +from pathlib import Path +from time import strftime, time +from uuid import uuid1 + +import requests +from fastapi import APIRouter, Depends, File, HTTPException, UploadFile +from fastapi.responses import StreamingResponse +from PIL import Image +from sqlalchemy.orm import Session + +from .. import schemas +from ..dependencies import get_db +from ..sql import crud + +router = APIRouter() + + +@router.get("/image/upload_history", response_model=list[schemas.image.Image], tags=['图片']) +def read_image_upload_history(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + pics = crud.get_pics(db, skip=skip, limit=limit) + return pics + + +@router.get("/image/detail/{pic_id}", response_model=schemas.image.Image, tags=['图片']) +def read_image_detail_by_id(pic_id: int, db: Session = Depends(get_db)): + db_pic = crud.get_pic(db, pic_id=pic_id) + if db_pic is None: + raise HTTPException(status_code=404, detail="没有找到图片") + return db_pic + + +@router.get("/image/{y}/{m}/{d}/{store_name}", tags=['图片']) +def get_image(store_name: str, y: str, m: str, d: str, db: Session = Depends(get_db)): + image_path = Path(Path.home()).joinpath( + 'Pictures').joinpath('upload_images').joinpath(f'{y}/{m}/{d}').joinpath(store_name) + try: + img_file = open(image_path, mode='rb') + except: + raise HTTPException(status_code=404, detail="没有找到图片") + media_type = mimetypes.guess_type(store_name)[0] + img_resp = BytesIO(img_file.read()) + img_file.close() + try: + ori_file_name = crud.get_pic_by_path( + db, file_path=f'{y}/{m}/{d}/{store_name}').file_name + except: + raise HTTPException(status_code=500, detail="无法连接数据库") + return StreamingResponse(content=img_resp, media_type=media_type, headers={'Content-Disposition': f'inline; filename={ori_file_name}'}) + + +@router.post("/image/upload", response_model=schemas.image.Image, tags=['图片']) +async def create_pic(pic: UploadFile, db: Session = Depends(get_db)): + allowFileType = ["image/jpeg", "image/gif", "image/png"] + if (pic.content_type not in allowFileType): + raise HTTPException(status_code=500, detail="只能上传图片文件") + print(pic.content_type) + upload_time = strftime('%Y/%m/%d') + picBytes = await pic.read() + fileSize = len(picBytes) + pilObj = Image.open(BytesIO(picBytes)) + picWidth = pilObj.size[0] + picHeight = pilObj.size[1] + await pic.seek(0) + image_path = Path(Path.home()).joinpath( + 'Pictures').joinpath('upload_images').joinpath(upload_time) + try: + Path.mkdir(image_path, parents=True) + except FileExistsError: + pass + ext_name = pic.filename.split('.')[-1] + file_name = f'{uuid1().hex}.{ext_name}' + db_pic = schemas.image.ImageCreate( + file_name=pic.filename, file_path=f'{upload_time}/{file_name}', size=fileSize, upload_time=round(int(time()*1000)), width=picWidth, height=picHeight) + # 尝试存储图片文件,失败则抛出500错误 + try: + with open(image_path.joinpath(file_name), mode='wb') as f: + f.write(await pic.read()) + except: + raise HTTPException(status_code=500, detail="文件存储失败") + await pic.close() + # 尝试存储图片信息到数据库,失败则抛出500错误并删除此前存储的图片文件 + try: + pic_obj = crud.create_pic(db, pic=db_pic) + return pic_obj + except: + image_path.joinpath(file_name).unlink() + raise HTTPException(status_code=500, detail="无法连接数据库") + + +# 获取给定 url 的图片的缩略图 + +@router.get('/thumbnail', tags=['图片']) +async def get_pic_thumb(url: str, w: int): + resp = requests.get(url) + im = Image.open(BytesIO(resp.content)) + size = w, im.size[1] + im.thumbnail(size) + ext_name = im.format + if (im.format == "JPEG"): + ext_name = 'jpg' + ext_name = ext_name.lower() + pic_buffer = BytesIO() + im.save(pic_buffer, format=im.format) + im.close() + resp_image = BytesIO(pic_buffer.getvalue()) + pic_buffer.close() + return StreamingResponse(content=resp_image, media_type='image/'+im.format.lower(), headers={'Content-Disposition': 'inline; filename=image.'+ext_name}) diff --git a/pics_server/schemas/image.py b/pics_server/schemas/image.py index 5b553fd..86d87a0 100644 --- a/pics_server/schemas/image.py +++ b/pics_server/schemas/image.py @@ -1,3 +1,4 @@ +from turtle import heading, width from pydantic import BaseModel @@ -5,7 +6,10 @@ class Image(BaseModel): id: int file_path: str file_name: str - upload_time: str + upload_time: int + size: int + width: int + height: int class Config: orm_mode = True @@ -14,4 +18,7 @@ class Image(BaseModel): class ImageCreate(BaseModel): file_path: str file_name: str - upload_time: str + upload_time: int + size: int + width: int + height: int diff --git a/pics_server/sql/crud.py b/pics_server/sql/crud.py index a5c78df..ceb8301 100644 --- a/pics_server/sql/crud.py +++ b/pics_server/sql/crud.py @@ -1,3 +1,5 @@ +from ctypes import sizeof +from turtle import width from sqlalchemy.orm import Session from .. import models, schemas @@ -17,7 +19,7 @@ def get_pics(db: Session, skip: int = 0, limit: int = 100): def create_pic(db: Session, pic: schemas.image.ImageCreate): db_pic = models.image.Image(file_path=pic.file_path, - file_name=pic.file_name, upload_time=pic.upload_time) + file_name=pic.file_name, upload_time=pic.upload_time, size=pic.size, width=pic.width, height=pic.height) db.add(db_pic) db.commit() return db_pic