app.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import os
  2. import sys
  3. import uuid
  4. import tempfile
  5. import pdfplumber
  6. from flask import Flask, request, jsonify, send_file
  7. from add_signature import find_signature_positions, add_signature_to_pdf
  8. from add_watermark import add_watermark_to_pdf
  9. from extract_table import extract_temp_time, extract_pdf_table_to_excel, extract_temp_by_datetime_pattern, allowed_file, \
  10. safe_filename, extract_temperature_data_from_pdf, extract_data_from_pdf_5
  11. from drag_signature import add_signature_at_position, add_multiple_signatures
  12. from process_image import create_process_image_route
  13. from generate_handwriting import create_handwriting_route
  14. from lib import Qiniu
  15. from werkzeug.utils import secure_filename
  16. from flask_cors import CORS
  17. app = Flask(__name__)
  18. UPLOAD_FOLDER = tempfile.gettempdir()
  19. app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
  20. CORS(app)
  21. # 确保temp目录存在
  22. temp_dir = "./temp"
  23. if not os.path.exists(temp_dir):
  24. os.makedirs(temp_dir)
  25. @app.route('/add_signature', methods=['POST'])
  26. def add_signature():
  27. try:
  28. # 获取请求参数
  29. data = request.get_json()
  30. pdf_url = data.get('pdf_url')
  31. if not pdf_url:
  32. return jsonify({"error": "缺少pdf_url参数"}), 400
  33. # 下载PDF文件
  34. local_pdf = Qiniu.download_file(pdf_url)
  35. # 查找签名位置(使用默认公章图片)
  36. signature_img = './static/报告专用章.png' # 确保项目目录下有这个文件
  37. positions = find_signature_positions(local_pdf)
  38. if not positions:
  39. os.remove(local_pdf)
  40. return jsonify({"error": "未找到签名位置"}), 400
  41. # 生成带公章的PDF
  42. signature_pdf = os.path.join("./temp", f"signature_{os.path.basename(local_pdf)}")
  43. add_signature_to_pdf(local_pdf, signature_pdf, signature_img, positions)
  44. # 上传到七牛云
  45. file_key = f"UpImage/{uuid.uuid4()}.pdf"
  46. new_pdf_url = Qiniu.upload_to_qiniu(signature_pdf, file_key)
  47. # 清理临时文件
  48. os.remove(local_pdf)
  49. os.remove(signature_pdf)
  50. return jsonify({
  51. "success": True,
  52. "signature_pdf_url": new_pdf_url
  53. })
  54. except Exception as e:
  55. return jsonify({
  56. "error": str(e),
  57. "success": False,
  58. }), 500
  59. @app.route('/add_watermark', methods=['POST'])
  60. def add_watermark():
  61. try:
  62. # 获取请求参数
  63. data = request.get_json()
  64. pdf_url = data.get('pdf_url')
  65. if not pdf_url:
  66. return jsonify({"error": "缺少pdf_url参数"}), 400
  67. # 下载PDF文件
  68. local_pdf = Qiniu.download_file(pdf_url)
  69. # 水印文件
  70. pdf_file_mark = './static/watermark.pdf' # 确保项目目录下有这个文件
  71. # 生成带公章的PDF
  72. watermark_pdf = os.path.join("./temp", f"watermark_{os.path.basename(local_pdf)}")
  73. add_watermark_to_pdf(local_pdf, pdf_file_mark, watermark_pdf)
  74. # 上传到七牛云
  75. file_key = f"UpImage/{uuid.uuid4()}.pdf"
  76. new_pdf_url = Qiniu.upload_to_qiniu(watermark_pdf, file_key)
  77. # 清理临时文件
  78. os.remove(local_pdf)
  79. os.remove(watermark_pdf)
  80. return jsonify({
  81. "success": True,
  82. "watermark_pdf_url": new_pdf_url
  83. })
  84. except Exception as e:
  85. return jsonify({
  86. "error": str(e),
  87. "success": False,
  88. }), 500
  89. @app.route('/extract_table', methods=['POST'])
  90. def extract_table():
  91. if 'file' not in request.files:
  92. return jsonify({'error': 'No file part'}), 400
  93. file = request.files['file']
  94. if file.filename == '':
  95. return jsonify({'error': 'No selected file'}), 400
  96. if file and allowed_file(file.filename):
  97. original_filename = file.filename
  98. filename = safe_filename(original_filename)
  99. # filename = secure_filename(safe_name)
  100. filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
  101. file.save(filepath)
  102. df = None
  103. with pdfplumber.open(filepath) as pdf:
  104. # 获取第一页
  105. first_page = pdf.pages[0]
  106. text = first_page.extract_text()
  107. if text:
  108. if "温湿度数据报告" in text:
  109. df = extract_pdf_table_to_excel(filepath)
  110. if "历史数据表" in text:
  111. df = extract_temp_time(filepath)
  112. if "设备汇总报告" in text:
  113. df = extract_temp_by_datetime_pattern(filepath)
  114. if "详细数据" in text:
  115. df = extract_temperature_data_from_pdf(filepath)
  116. else:
  117. df = extract_data_from_pdf_5(filepath)
  118. if df is None:
  119. os.remove(filepath)
  120. return jsonify({'error': '所有处理方法均失败'}), 400
  121. # 保存Excel文件
  122. output_filename = filename.replace('.pdf', '.xlsx')
  123. output_path = os.path.join(app.config['UPLOAD_FOLDER'], output_filename)
  124. df.to_excel(output_path, index=False, engine='openpyxl')
  125. # 删除上传的PDF文件
  126. os.remove(filepath)
  127. # 返回Excel文件
  128. try:
  129. return send_file(
  130. output_path,
  131. as_attachment=True,
  132. download_name=output_filename,
  133. mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  134. )
  135. finally:
  136. # 确保临时文件最终被删除
  137. try:
  138. os.remove(output_path)
  139. except:
  140. pass
  141. else:
  142. return jsonify({'error': 'Invalid file type'}), 400
  143. @app.route('/upload_pdf', methods=['POST'])
  144. def upload_pdf():
  145. """
  146. 上传PDF文件到服务器并返回URL
  147. """
  148. try:
  149. if 'file' not in request.files:
  150. return jsonify({"error": "没有文件"}), 400
  151. file = request.files['file']
  152. if file.filename == '':
  153. return jsonify({"error": "文件名为空"}), 400
  154. if not file.filename.lower().endswith('.pdf'):
  155. return jsonify({"error": "只支持PDF文件"}), 400
  156. # 保存临时文件
  157. filename = secure_filename(file.filename)
  158. temp_pdf = os.path.join("./temp", f"upload_{uuid.uuid4()}.pdf")
  159. file.save(temp_pdf)
  160. # 上传到七牛云
  161. file_key = f"UpImage/{uuid.uuid4()}.pdf"
  162. pdf_url = Qiniu.upload_to_qiniu(temp_pdf, file_key)
  163. # 清理临时文件
  164. try:
  165. os.remove(temp_pdf)
  166. except:
  167. pass
  168. return jsonify({
  169. "success": True,
  170. "pdf_url": pdf_url
  171. })
  172. except Exception as e:
  173. return jsonify({
  174. "error": str(e),
  175. "success": False,
  176. }), 500
  177. @app.route('/upload_signature', methods=['POST'])
  178. def upload_signature():
  179. """
  180. 上传签名图片文件到服务器并返回URL
  181. """
  182. try:
  183. if 'file' not in request.files:
  184. return jsonify({"error": "没有文件"}), 400
  185. file = request.files['file']
  186. if file.filename == '':
  187. return jsonify({"error": "文件名为空"}), 400
  188. # 检查文件类型(支持常见的图片格式)
  189. allowed_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'}
  190. filename_lower = file.filename.lower()
  191. if not any(filename_lower.endswith(ext) for ext in allowed_extensions):
  192. return jsonify({"error": "只支持图片文件(png, jpg, jpeg, gif, bmp, webp)"}), 400
  193. # 保存临时文件
  194. filename = secure_filename(file.filename)
  195. # 获取文件扩展名
  196. file_ext = os.path.splitext(filename)[1] or '.png'
  197. temp_signature = os.path.join("./temp", f"upload_signature_{uuid.uuid4()}{file_ext}")
  198. file.save(temp_signature)
  199. # 上传到七牛云
  200. file_key = f"UpImage/{uuid.uuid4()}{file_ext}"
  201. signature_url = Qiniu.upload_to_qiniu(temp_signature, file_key)
  202. # 清理临时文件
  203. try:
  204. os.remove(temp_signature)
  205. except:
  206. pass
  207. return jsonify({
  208. "success": True,
  209. "signature_url": signature_url
  210. })
  211. except Exception as e:
  212. return jsonify({
  213. "error": str(e),
  214. "success": False,
  215. }), 500
  216. @app.route('/drag_signature', methods=['POST'])
  217. def drag_signature():
  218. """
  219. 在PDF上添加签名或电子章(支持拖放)
  220. 请求参数:
  221. {
  222. "pdf_url": "PDF文件URL",
  223. "signatures": [
  224. {
  225. "signature_url": "签名/电子章URL或base64字符串(支持data URL格式,如data:image/png;base64,...)",
  226. "page_num": 页码(从0开始),
  227. "x": X坐标(相对于页面左上角,单位:点),
  228. "y": Y坐标(相对于页面左上角,单位:点),
  229. "width": 宽度(可选,单位:点),
  230. "height": 高度(可选,单位:点)
  231. }
  232. ]
  233. }
  234. """
  235. try:
  236. # 获取请求参数
  237. data = request.get_json()
  238. pdf_url = data.get('pdf_url')
  239. signatures = data.get('signatures', [])
  240. if not pdf_url:
  241. return jsonify({"error": "缺少pdf_url参数"}), 400
  242. if not signatures or len(signatures) == 0:
  243. return jsonify({"error": "缺少signatures参数或签名列表为空"}), 400
  244. # 下载PDF文件
  245. local_pdf = Qiniu.download_file(pdf_url)
  246. # 生成带签名的PDF
  247. output_pdf = os.path.join("./temp", f"drag_signature_{uuid.uuid4()}.pdf")
  248. # 添加多个签名
  249. add_multiple_signatures(local_pdf, output_pdf, signatures)
  250. # 上传到七牛云
  251. file_key = f"UpImage/{uuid.uuid4()}.pdf"
  252. new_pdf_url = Qiniu.upload_to_qiniu(output_pdf, file_key)
  253. # 清理临时文件
  254. try:
  255. os.remove(local_pdf)
  256. os.remove(output_pdf)
  257. except:
  258. pass
  259. return jsonify({
  260. "success": True,
  261. "pdf_url": new_pdf_url
  262. })
  263. except Exception as e:
  264. return jsonify({
  265. "error": str(e),
  266. "success": False,
  267. }), 500
  268. # 注册图片处理接口
  269. create_process_image_route(app)
  270. # 注册手写字体生成接口
  271. create_handwriting_route(app)
  272. @app.route('/font_preview')
  273. def font_preview():
  274. """字体预览页面"""
  275. return send_file('font_preview.html')
  276. @app.route('/font_comparison')
  277. def font_comparison():
  278. """字体对比预览页面"""
  279. return send_file('font_comparison.html')
  280. @app.route('/drag_signature')
  281. def drag_signature_page():
  282. """PDF签名拖放工具页面"""
  283. return send_file('drag_signature.html')
  284. if __name__ == '__main__':
  285. print("项目地址:", os.path.dirname(__file__))
  286. if len(sys.argv) != 2:
  287. print("请填写端口号")
  288. sys.exit()
  289. # app.debug = True # 设置调试模式,生产模式的时候要关掉debug
  290. # app.config['JSON_AS_ASCII'] = False
  291. app.run(host='0.0.0.0', port=6500, debug=True)