mer1.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import openpyxl
  2. from openpyxl.styles import Font, Alignment, Border, Side, PatternFill, NamedStyle
  3. from openpyxl.drawing.image import Image
  4. from openpyxl.utils import get_column_letter
  5. from openpyxl.worksheet.merge import MergedCellRange
  6. import os
  7. import copy
  8. def copy_cell_style_complete(src_cell, dest_cell):
  9. """
  10. 完整复制单元格所有样式属性
  11. """
  12. try:
  13. # 1. 复制字体
  14. if src_cell.font:
  15. dest_cell.font = Font(
  16. name=src_cell.font.name,
  17. size=src_cell.font.size,
  18. bold=src_cell.font.bold,
  19. italic=src_cell.font.italic,
  20. underline=src_cell.font.underline,
  21. strike=src_cell.font.strike,
  22. color=copy.copy(src_cell.font.color)
  23. )
  24. # 2. 复制对齐方式
  25. if src_cell.alignment:
  26. dest_cell.alignment = Alignment(
  27. horizontal=src_cell.alignment.horizontal,
  28. vertical=src_cell.alignment.vertical,
  29. text_rotation=src_cell.alignment.text_rotation,
  30. wrap_text=src_cell.alignment.wrap_text,
  31. shrink_to_fit=src_cell.alignment.shrink_to_fit,
  32. indent=src_cell.alignment.indent
  33. )
  34. # 3. 复制边框
  35. if src_cell.border:
  36. dest_cell.border = Border(
  37. left=copy_border_side(src_cell.border.left),
  38. right=copy_border_side(src_cell.border.right),
  39. top=copy_border_side(src_cell.border.top),
  40. bottom=copy_border_side(src_cell.border.bottom)
  41. )
  42. # 4. 复制填充颜色
  43. if src_cell.fill:
  44. if src_cell.fill.fill_type == 'patternFill':
  45. dest_cell.fill = PatternFill(
  46. fill_type=src_cell.fill.fill_type,
  47. start_color=src_cell.fill.start_color,
  48. end_color=src_cell.fill.end_color,
  49. patternType=src_cell.fill.patternType
  50. )
  51. elif src_cell.fill.fill_type == 'gradientFill':
  52. # 处理渐变填充(如果需要)
  53. pass
  54. # 5. 复制数字格式
  55. dest_cell.number_format = src_cell.number_format
  56. # 6. 复制保护设置
  57. dest_cell.protection = copy.copy(src_cell.protection)
  58. except Exception as e:
  59. print(f"复制单元格样式时出错: {e}")
  60. def copy_border_side(side):
  61. """复制边框边"""
  62. if side and side.style:
  63. return Side(
  64. style=side.style,
  65. color=copy.copy(side.color)
  66. )
  67. return None
  68. def copy_merged_cells(src_ws, dest_ws, row_offset=0, col_offset=0):
  69. """
  70. 复制合并单元格设置
  71. """
  72. try:
  73. for merged_range in src_ws.merged_cells.ranges:
  74. # 调整合并单元格的位置
  75. min_row = merged_range.min_row + row_offset
  76. max_row = merged_range.max_row + row_offset
  77. min_col = merged_range.min_col + col_offset
  78. max_col = merged_range.max_col + col_offset
  79. # 在目标工作表中创建合并单元格
  80. dest_ws.merge_cells(
  81. start_row=min_row,
  82. start_column=min_col,
  83. end_row=max_row,
  84. end_column=max_col
  85. )
  86. print(f"复制合并单元格: {get_column_letter(min_col)}{min_row}:{get_column_letter(max_col)}{max_row}")
  87. except Exception as e:
  88. print(f"复制合并单元格时出错: {e}")
  89. def copy_row_heights_complete(src_ws, dest_ws, start_row=1):
  90. """
  91. 完整复制行高设置
  92. """
  93. try:
  94. for row_idx, row_dim in src_ws.row_dimensions.items():
  95. if row_dim.height is not None:
  96. dest_row = start_row + row_idx - 1
  97. dest_ws.row_dimensions[dest_row].height = row_dim.height
  98. # 复制其他行属性
  99. dest_ws.row_dimensions[dest_row].hidden = row_dim.hidden
  100. except Exception as e:
  101. print(f"复制行高时出错: {e}")
  102. def copy_column_widths_complete(src_ws, dest_ws, start_col=1):
  103. """
  104. 完整复制列宽设置
  105. """
  106. try:
  107. for col_idx, col_dim in src_ws.column_dimensions.items():
  108. if col_dim.width is not None:
  109. dest_col_letter = get_column_letter(start_col + (ord(col_idx) - ord('A')))
  110. dest_ws.column_dimensions[dest_col_letter].width = col_dim.width
  111. # 复制其他列属性
  112. dest_ws.column_dimensions[dest_col_letter].hidden = col_dim.hidden
  113. except Exception as e:
  114. print(f"复制列宽时出错: {e}")
  115. def copy_images_improved(src_ws, dest_ws, row_offset=0):
  116. """
  117. 改进的图片复制函数,处理各种图片嵌入方式
  118. """
  119. try:
  120. # 方法1: 直接复制图片对象
  121. for img in src_ws._images:
  122. try:
  123. # 创建新的图片对象
  124. if hasattr(img, 'ref') and img.ref:
  125. # 如果有图片引用,使用引用创建新图片
  126. new_img = Image(img.ref)
  127. elif hasattr(img, 'path') and img.path and os.path.exists(img.path):
  128. # 如果有图片路径,使用路径创建新图片
  129. new_img = Image(img.path)
  130. else:
  131. # 尝试从图片数据创建
  132. img_data = img._data()
  133. img_stream = io.BytesIO(img_data)
  134. new_img = Image(img_stream)
  135. # 设置图片位置(考虑行偏移)
  136. if hasattr(img, 'anchor'):
  137. new_img.anchor = img.anchor
  138. # 调整行位置
  139. if row_offset > 0:
  140. # 这里需要根据具体锚点类型调整
  141. if hasattr(new_img.anchor, '_from') and hasattr(new_img.anchor._from, 'row'):
  142. new_img.anchor._from.row += row_offset
  143. if hasattr(new_img.anchor, 'to') and hasattr(new_img.anchor.to, 'row'):
  144. new_img.anchor.to.row += row_offset
  145. dest_ws.add_image(new_img)
  146. print(f"成功复制图片到位置: {new_img.anchor}")
  147. except Exception as img_error:
  148. print(f"复制单个图片时出错: {img_error}")
  149. continue
  150. except Exception as e:
  151. print(f"图片复制过程中出错: {e}")
  152. def copy_worksheet_complete(src_ws, dest_ws, start_row=1, start_col=1):
  153. """
  154. 完整复制工作表的所有内容和样式
  155. """
  156. row_offset = start_row - 1
  157. col_offset = start_col - 1
  158. # 1. 先复制合并单元格
  159. copy_merged_cells(src_ws, dest_ws, row_offset, col_offset)
  160. # 2. 复制行高和列宽
  161. copy_row_heights_complete(src_ws, dest_ws, start_row)
  162. copy_column_widths_complete(src_ws, dest_ws, start_col)
  163. # 3. 复制单元格内容和样式
  164. for row_idx, row in enumerate(src_ws.iter_rows(), 1):
  165. for col_idx, cell in enumerate(row, 1):
  166. dest_row = row_idx + row_offset
  167. dest_col = col_idx + col_offset
  168. dest_cell = dest_ws.cell(
  169. row=dest_row,
  170. column=dest_col,
  171. value=cell.value
  172. )
  173. copy_cell_style_complete(cell, dest_cell)
  174. # 4. 复制图片
  175. copy_images_improved(src_ws, dest_ws, row_offset)
  176. def merge_fashion_tables_complete(file1, file2, output_file):
  177. """
  178. 完整保留样式的服装搭配表格合并
  179. """
  180. try:
  181. # 加载工作簿
  182. wb1 = openpyxl.load_workbook(file1)
  183. wb2 = openpyxl.load_workbook(file2)
  184. # 创建新工作簿
  185. merged_wb = openpyxl.Workbook()
  186. merged_ws = merged_wb.active
  187. merged_ws.title = "合并服装搭配表"
  188. # 获取工作表
  189. ws1 = wb1.active
  190. ws2 = wb2.active
  191. print("开始合并第一个表格...")
  192. # 复制第一个表格(从第1行开始)
  193. copy_worksheet_complete(ws1, merged_ws, start_row=1, start_col=1)
  194. # 计算第一个表格的行数
  195. first_table_rows = ws1.max_row
  196. print("开始合并第二个表格...")
  197. # 复制第二个表格(从第一个表格末尾+2行开始,留出间隔)
  198. copy_worksheet_complete(ws2, merged_ws, start_row=first_table_rows + 2, start_col=1)
  199. # 保存合并结果
  200. merged_wb.save(output_file)
  201. print(f"表格合并完成!输出文件: {output_file}")
  202. # 验证结果
  203. verify_merge_complete(output_file, ws1, ws2)
  204. return True
  205. except Exception as e:
  206. print(f"合并过程中出现错误: {e}")
  207. import traceback
  208. traceback.print_exc()
  209. return False
  210. def verify_merge_complete(output_file, ws1, ws2):
  211. """
  212. 验证合并结果是否完整
  213. """
  214. try:
  215. wb = openpyxl.load_workbook(output_file)
  216. ws = wb.active
  217. print("\n=== 合并结果验证 ===")
  218. print(f"总行数: {ws.max_row}")
  219. print(f"总列数: {ws.max_column}")
  220. print(f"合并单元格数量: {len(ws.merged_cells.ranges)}")
  221. print(f"图片数量: {len(ws._images)}")
  222. # 检查样式
  223. sample_cell = ws.cell(row=1, column=1)
  224. if sample_cell.fill.start_color:
  225. print(f"示例单元格填充颜色: {sample_cell.fill.start_color}")
  226. if sample_cell.alignment:
  227. print(f"示例单元格对齐方式: {sample_cell.alignment.horizontal}")
  228. wb.close()
  229. except Exception as e:
  230. print(f"验证过程中出错: {e}")
  231. # 使用示例
  232. if __name__ == "__main__":
  233. file1 = "./output/xxxxxxxxxxx.xlsx"
  234. file2 = "./output/10CL6E1U086Y.xlsx"
  235. output = "merged_data.xlsx"
  236. if os.path.exists(file1) and os.path.exists(file2):
  237. print("开始合并服装搭配表格(完整样式保留)...")
  238. success = merge_fashion_tables_complete(file1, file2, output)
  239. if success:
  240. print("合并成功!")
  241. else:
  242. print("合并失败!")
  243. else:
  244. print("请确保两个Excel文件都存在!")