Update Doors_Schedule.py
Browse files- Doors_Schedule.py +10 -395
Doors_Schedule.py
CHANGED
|
@@ -13,6 +13,13 @@ from PyPDF2 import PdfReader
|
|
| 13 |
from PyPDF2.generic import TextStringObject
|
| 14 |
import numpy as np
|
| 15 |
import cv2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
def convert2img(path):
|
|
@@ -392,67 +399,6 @@ def get_st_op_pattern(selected_columns, user_input):
|
|
| 392 |
return None
|
| 393 |
|
| 394 |
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
def get_similar_colors(selected_columns_new):
|
| 398 |
-
def generate_rgb():
|
| 399 |
-
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) # RGB tuple
|
| 400 |
-
|
| 401 |
-
unique_keys = selected_columns_new['door_type'].unique()
|
| 402 |
-
key_colors = {key: generate_rgb() for key in unique_keys} # Assign a unique RGB color to each key
|
| 403 |
-
|
| 404 |
-
# Create dictionary storing values, colors, and widths
|
| 405 |
-
if 'structural_opening' in selected_columns_new.columns:
|
| 406 |
-
col_dict = defaultdict(lambda: {'values': [], 'color': None, 'widths': []})
|
| 407 |
-
else:
|
| 408 |
-
col_dict = defaultdict(lambda: {'values': [], 'color': None, 'widths': [], 'heights': []})
|
| 409 |
-
if selected_columns_new.shape[1] == 2:
|
| 410 |
-
col_dict = defaultdict(lambda: {'values': [], 'color': None})
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
for _, row in selected_columns_new.iterrows():
|
| 414 |
-
key = row['door_type']
|
| 415 |
-
col_dict[key]['values'].append(row['door_id'])
|
| 416 |
-
if 'structural_opening' in selected_columns_new.columns:
|
| 417 |
-
col_dict[key]['widths'].append(row['structural_opening']) # Add structural opening
|
| 418 |
-
else:
|
| 419 |
-
if selected_columns_new.shape[1] > 2:
|
| 420 |
-
col_dict[key]['widths'].append(row['width']) # Assuming 'widht' is a typo for 'width'
|
| 421 |
-
col_dict[key]['heights'].append(row['height'])
|
| 422 |
-
col_dict[key]['color'] = key_colors[key] # Assign the unique RGB color
|
| 423 |
-
|
| 424 |
-
# Convert defaultdict to a normal dictionary
|
| 425 |
-
col_dict = dict(col_dict)
|
| 426 |
-
return col_dict
|
| 427 |
-
|
| 428 |
-
def get_flattened_tuples_list(col_dict):
|
| 429 |
-
tuples_list = []
|
| 430 |
-
|
| 431 |
-
for key, values_dict in col_dict.items():
|
| 432 |
-
if 'heights' in values_dict and 'widths' in values_dict:
|
| 433 |
-
# Case: Both widths and heights present
|
| 434 |
-
tuples_list.append([
|
| 435 |
-
(value, width, height, values_dict["color"])
|
| 436 |
-
for value, width, height in zip(values_dict['values'], values_dict['widths'], values_dict['heights'])
|
| 437 |
-
])
|
| 438 |
-
elif 'widths' in values_dict:
|
| 439 |
-
# Case: Only widths present
|
| 440 |
-
tuples_list.append([
|
| 441 |
-
(value, width, values_dict["color"])
|
| 442 |
-
for value, width in zip(values_dict['values'], values_dict['widths'])
|
| 443 |
-
])
|
| 444 |
-
else:
|
| 445 |
-
# Case: Neither widths nor heights
|
| 446 |
-
tuples_list.append([
|
| 447 |
-
(value, values_dict["color"])
|
| 448 |
-
for value in values_dict['values']
|
| 449 |
-
])
|
| 450 |
-
|
| 451 |
-
# Flatten the list of lists
|
| 452 |
-
flattened_list = [item for sublist in tuples_list for item in sublist]
|
| 453 |
-
|
| 454 |
-
return flattened_list
|
| 455 |
-
|
| 456 |
def find_text_in_plan(label, x):
|
| 457 |
substring_coordinates = []
|
| 458 |
words = []
|
|
@@ -465,6 +411,8 @@ def find_text_in_plan(label, x):
|
|
| 465 |
words.append(tpl[4])
|
| 466 |
return substring_coordinates, words, point_list
|
| 467 |
|
|
|
|
|
|
|
| 468 |
def get_word_locations_plan(flattened_list, plan_texts):
|
| 469 |
locations = []
|
| 470 |
not_found = []
|
|
@@ -592,142 +540,6 @@ def get_widths_bb_format(cleaned_width, kelma):
|
|
| 592 |
return widths
|
| 593 |
|
| 594 |
|
| 595 |
-
def get_secondary_info(dfs, user_patterns):
|
| 596 |
-
selected_columns = []
|
| 597 |
-
selected_columns_new = None # Initialize selected_columns_new to None
|
| 598 |
-
|
| 599 |
-
for i in range(len(dfs)):
|
| 600 |
-
cell_columns_appearance = flexible_search(dfs[i], user_patterns)
|
| 601 |
-
cell_matches, col_matches = analyse_cell_columns(cell_columns_appearance)
|
| 602 |
-
|
| 603 |
-
|
| 604 |
-
clmn_name = user_patterns
|
| 605 |
-
|
| 606 |
-
|
| 607 |
-
if len(cell_matches) == 0 and len(col_matches) == 0:
|
| 608 |
-
print(f"this is df {i}, SEARCH IN ANOTHER DF")
|
| 609 |
-
|
| 610 |
-
else:
|
| 611 |
-
#IN COLUMNS
|
| 612 |
-
if len(col_matches) == len(user_patterns):
|
| 613 |
-
column_index_list = get_column_index(col_matches)
|
| 614 |
-
print(f"this is df {i} mawgooda fel columns, check el df length 3ashan law el details fe table tany")
|
| 615 |
-
#print(len(clm_idx))
|
| 616 |
-
#details in another table
|
| 617 |
-
print(column_index_list)
|
| 618 |
-
if len(dfs[i]) <10:
|
| 619 |
-
selected_columns_new = details_in_another_table(clmn_name, column_index_list, dfs[i], dfs)
|
| 620 |
-
#break
|
| 621 |
-
#other_matches = details_in_another_table_mod(clmn_name, clmn_idx, dfs[i], dfs)
|
| 622 |
-
#details in the same table
|
| 623 |
-
if len(dfs[i]) >10:
|
| 624 |
-
selected_columns_new = generate_current_table_without_cropping(column_index_list,dfs[i])
|
| 625 |
-
#break
|
| 626 |
-
|
| 627 |
-
#IN CELLS
|
| 628 |
-
if len(cell_matches) == len(user_patterns):
|
| 629 |
-
row_index_list, column_index_list = get_row_column_indices(cell_matches)
|
| 630 |
-
print(f"this is df {i} mawgooda fel cells, check el df length 3ashan law el details fe table tany")
|
| 631 |
-
|
| 632 |
-
#details in another table
|
| 633 |
-
if len(dfs[i]) <10:
|
| 634 |
-
#selected_columns_new = details_in_another_table(clmn_name, clmn_idx, dfs[i], dfs)
|
| 635 |
-
selected_columns_new = details_in_another_table(clmn_name, column_index_list, dfs[i], dfs)
|
| 636 |
-
break
|
| 637 |
-
#other_matches = details_in_another_table_mod(clmn_name, clmn_idx, dfs[i], dfs)
|
| 638 |
-
#details in the same table
|
| 639 |
-
if len(dfs[i]) >10:
|
| 640 |
-
print(f"this is df {i} call crop_rename_table(indices, clmn_name, clmn_idx,df)")
|
| 641 |
-
selected_columns_new = crop_rename_table(row_index_list, clmn_name, column_index_list,dfs[i])
|
| 642 |
-
break
|
| 643 |
-
return selected_columns_new
|
| 644 |
-
|
| 645 |
-
def get_similar_colors_secondary(selected_columns_new, user_input):
|
| 646 |
-
def generate_rgb():
|
| 647 |
-
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
| 648 |
-
|
| 649 |
-
unique_keys = selected_columns_new['door_type'].unique()
|
| 650 |
-
key_colors = {key: generate_rgb() for key in unique_keys}
|
| 651 |
-
|
| 652 |
-
# Only exclude actual None values; allow empty string column names if they exist in the DataFrame
|
| 653 |
-
extra_fields = [col for col in user_input[4:] if col is not None]
|
| 654 |
-
|
| 655 |
-
def col_template():
|
| 656 |
-
d = {
|
| 657 |
-
'values': [],
|
| 658 |
-
'color': None
|
| 659 |
-
}
|
| 660 |
-
if 'structural_opening' in selected_columns_new.columns:
|
| 661 |
-
d['widths'] = []
|
| 662 |
-
elif selected_columns_new.shape[1] > 2:
|
| 663 |
-
d['widths'] = []
|
| 664 |
-
d['heights'] = []
|
| 665 |
-
for field in extra_fields:
|
| 666 |
-
d[field] = []
|
| 667 |
-
return d
|
| 668 |
-
|
| 669 |
-
col_dict = defaultdict(col_template)
|
| 670 |
-
|
| 671 |
-
for _, row in selected_columns_new.iterrows():
|
| 672 |
-
key = row['door_type']
|
| 673 |
-
col_dict[key]['values'].append(row['door_id'])
|
| 674 |
-
|
| 675 |
-
if 'structural_opening' in selected_columns_new.columns:
|
| 676 |
-
col_dict[key]['widths'].append(row['structural_opening'])
|
| 677 |
-
elif selected_columns_new.shape[1] > 2:
|
| 678 |
-
col_dict[key]['widths'].append(row.get('width', 0))
|
| 679 |
-
col_dict[key]['heights'].append(row.get('height', 0))
|
| 680 |
-
|
| 681 |
-
for field in extra_fields:
|
| 682 |
-
col_dict[key][field].append(row.get(field, None))
|
| 683 |
-
|
| 684 |
-
col_dict[key]['color'] = key_colors[key]
|
| 685 |
-
|
| 686 |
-
return dict(col_dict)
|
| 687 |
-
|
| 688 |
-
'''def get_width_info_tobeprinted_secondary(new_data, main_info, secondary_info):
|
| 689 |
-
width_info_tobeprinted = []
|
| 690 |
-
secondary_info_tobeprinted = []
|
| 691 |
-
|
| 692 |
-
if len(main_info) == 2 and len(secondary_info) == 1:
|
| 693 |
-
for coords, label, color, acous in new_data:
|
| 694 |
-
secondary_info_tobeprinted.append(acous)
|
| 695 |
-
|
| 696 |
-
|
| 697 |
-
if len(main_info) == 2 and len(secondary_info) == 2:
|
| 698 |
-
for coords, label, color, acous, fire in new_data:
|
| 699 |
-
secondary_info_tobeprinted.append((acous, fire))
|
| 700 |
-
|
| 701 |
-
if len(main_info) == 3 and len(secondary_info) == 1:
|
| 702 |
-
for coords, label, width, color, acous in new_data:
|
| 703 |
-
width_info_tobeprinted.append(width)
|
| 704 |
-
secondary_info_tobeprinted.append(acous)
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
if len(main_info) == 3 and len(secondary_info) == 2:
|
| 708 |
-
for coords, label, width, color, acous, fire in new_data:
|
| 709 |
-
width_info_tobeprinted.append(width)
|
| 710 |
-
secondary_info_tobeprinted.append((acous, fire))
|
| 711 |
-
|
| 712 |
-
if len(main_info) == 4 and len(secondary_info) == 1:
|
| 713 |
-
for coords, label, width, height, color, acous in new_data:
|
| 714 |
-
w = re.sub(r",", "", width)
|
| 715 |
-
h = re.sub(r",", "", height)
|
| 716 |
-
w = int(float(w))
|
| 717 |
-
h = int(float(h))
|
| 718 |
-
width_info_tobeprinted.append(f"{w} mm wide x {h} mm high")
|
| 719 |
-
secondary_info_tobeprinted.append(acous)
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
if len(main_info) == 4 and len(secondary_info) == 2:
|
| 723 |
-
for coords, label, width, height, color, acous, fire in new_data:
|
| 724 |
-
w = re.sub(r",", "", width)
|
| 725 |
-
h = re.sub(r",", "", height)
|
| 726 |
-
w = int(float(w))
|
| 727 |
-
h = int(float(h))
|
| 728 |
-
width_info_tobeprinted.append(f"{w} mm wide x {h} mm high")
|
| 729 |
-
secondary_info_tobeprinted.append((acous, fire))
|
| 730 |
-
return width_info_tobeprinted, secondary_info_tobeprinted'''
|
| 731 |
|
| 732 |
def get_width_info_tobeprinted_secondary(new_data, main_info, secondary_info):
|
| 733 |
width_info_tobeprinted = []
|
|
@@ -773,51 +585,6 @@ def get_width_info_tobeprinted_secondary(new_data, main_info, secondary_info):
|
|
| 773 |
secondary_info_tobeprinted.append((acous, fire))
|
| 774 |
return width_info_tobeprinted, secondary_info_tobeprinted
|
| 775 |
|
| 776 |
-
def get_flattened_tuples_list_SECONDARY(col_dict):
|
| 777 |
-
tuples_list = []
|
| 778 |
-
|
| 779 |
-
for key, values_dict in col_dict.items():
|
| 780 |
-
# Find actual keys containing "Acoustic" and "Fire"
|
| 781 |
-
acoustic_key = next((k for k in values_dict if 'acoustic' in k.lower()), None)
|
| 782 |
-
fire_key = next((k for k in values_dict if 'fire' in k.lower()), None)
|
| 783 |
-
|
| 784 |
-
acoustic_values = values_dict.get(acoustic_key, [None] * len(values_dict['values'])) if acoustic_key else [None] * len(values_dict['values'])
|
| 785 |
-
fire_values = values_dict.get(fire_key, [None] * len(values_dict['values'])) if fire_key else [None] * len(values_dict['values'])
|
| 786 |
-
|
| 787 |
-
if 'heights' in values_dict and 'widths' in values_dict:
|
| 788 |
-
tuples_list.append([
|
| 789 |
-
(value, width, height, values_dict["color"], acoustic, fire)
|
| 790 |
-
for value, width, height, acoustic, fire in zip(
|
| 791 |
-
values_dict['values'],
|
| 792 |
-
values_dict['widths'],
|
| 793 |
-
values_dict['heights'],
|
| 794 |
-
acoustic_values,
|
| 795 |
-
fire_values
|
| 796 |
-
)
|
| 797 |
-
])
|
| 798 |
-
elif 'widths' in values_dict:
|
| 799 |
-
tuples_list.append([
|
| 800 |
-
(value, width, values_dict["color"], acoustic, fire)
|
| 801 |
-
for value, width, acoustic, fire in zip(
|
| 802 |
-
values_dict['values'],
|
| 803 |
-
values_dict['widths'],
|
| 804 |
-
acoustic_values,
|
| 805 |
-
fire_values
|
| 806 |
-
)
|
| 807 |
-
])
|
| 808 |
-
else:
|
| 809 |
-
tuples_list.append([
|
| 810 |
-
(value, values_dict["color"], acoustic, fire)
|
| 811 |
-
for value, acoustic, fire in zip(
|
| 812 |
-
values_dict['values'],
|
| 813 |
-
acoustic_values,
|
| 814 |
-
fire_values
|
| 815 |
-
)
|
| 816 |
-
])
|
| 817 |
-
|
| 818 |
-
flattened_list = [item for sublist in tuples_list for item in sublist]
|
| 819 |
-
|
| 820 |
-
return flattened_list
|
| 821 |
|
| 822 |
def get_word_locations_plan_secondary(flattened_list, plan_texts, main_info, secondary_info):
|
| 823 |
#hena fe 7alet en keda keda fe secondary information
|
|
@@ -874,9 +641,6 @@ def get_word_locations_plan_secondary(flattened_list, plan_texts, main_info, sec
|
|
| 874 |
return locations, not_found
|
| 875 |
|
| 876 |
### newest, accept combined table
|
| 877 |
-
from collections import defaultdict
|
| 878 |
-
import random
|
| 879 |
-
|
| 880 |
def get_similar_colors_all(selected_columns_new):
|
| 881 |
def generate_rgb():
|
| 882 |
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
|
@@ -995,44 +759,6 @@ def get_cleaned_data_secondary(locations, main_info, secondary_info):
|
|
| 995 |
|
| 996 |
return new_data
|
| 997 |
|
| 998 |
-
from collections import defaultdict
|
| 999 |
-
|
| 1000 |
-
def get_cleaned_data_gpt(locations):
|
| 1001 |
-
processed = defaultdict(int)
|
| 1002 |
-
new_data = []
|
| 1003 |
-
|
| 1004 |
-
for entry in locations:
|
| 1005 |
-
coords = entry[0]
|
| 1006 |
-
label = entry[1]
|
| 1007 |
-
index = processed[label] % len(coords) if len(coords) > 1 else 0
|
| 1008 |
-
new_coord = [coords[index]] if len(coords) > 1 else coords
|
| 1009 |
-
processed[label] += 1 if len(coords) > 1 else 0
|
| 1010 |
-
|
| 1011 |
-
# Rebuild the entry with updated coordinates
|
| 1012 |
-
new_entry = (new_coord,) + entry[1:]
|
| 1013 |
-
new_data.append(new_entry)
|
| 1014 |
-
|
| 1015 |
-
return new_data
|
| 1016 |
-
|
| 1017 |
-
'''def get_secondary_tobeprinted_clean(selected_secondary_info, secondary_tobeprinted, secondary_info):
|
| 1018 |
-
secondary_printed_clean = []
|
| 1019 |
-
if len(secondary_info) == 1:
|
| 1020 |
-
if any('Acoustic' in col for col in selected_secondary_info.columns):
|
| 1021 |
-
for acous in secondary_tobeprinted:
|
| 1022 |
-
new_text = f"acoustic rating: {acous}"
|
| 1023 |
-
secondary_printed_clean.append(new_text)
|
| 1024 |
-
if any('Fire' in col for col in selected_secondary_info.columns):
|
| 1025 |
-
for fire in secondary_tobeprinted:
|
| 1026 |
-
new_text = f"fire rating: {fire}"
|
| 1027 |
-
secondary_printed_clean.append(new_text)
|
| 1028 |
-
if len(secondary_info) == 2:
|
| 1029 |
-
for acous, fire in secondary_tobeprinted:
|
| 1030 |
-
new_text = f"fire rating: {fire}; acoustic rating: {acous}"
|
| 1031 |
-
secondary_printed_clean.append(new_text)
|
| 1032 |
-
print(new_text)
|
| 1033 |
-
return secondary_printed_clean'''
|
| 1034 |
-
|
| 1035 |
-
|
| 1036 |
def get_secondary_tobeprinted_clean(selected_secondary_info, secondary_tobeprinted, secondary_info):
|
| 1037 |
secondary_printed_clean = []
|
| 1038 |
if len(secondary_info) == 1:
|
|
@@ -1201,11 +927,6 @@ def add_bluebeam_count_annotations_secondary(pdf_bytes, locations, main_info, se
|
|
| 1201 |
|
| 1202 |
return output_stream.getvalue() # Return the modified PDF as bytes
|
| 1203 |
|
| 1204 |
-
def get_user_input(user_words):
|
| 1205 |
-
user_input = []
|
| 1206 |
-
for item in user_words:
|
| 1207 |
-
user_input.append(item[0])
|
| 1208 |
-
return user_input
|
| 1209 |
|
| 1210 |
def modify_author_in_pypdf2(pdf_bytes, new_authors):
|
| 1211 |
pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
|
|
@@ -1238,96 +959,10 @@ def modify_author_in_pypdf2(pdf_bytes, new_authors):
|
|
| 1238 |
|
| 1239 |
return output_stream.read()
|
| 1240 |
|
| 1241 |
-
# return output_stream.getvalue() # Return modified PDF as bytes
|
| 1242 |
-
|
| 1243 |
-
def process_pdf_secondary(input_pdf_path, output_pdf_path, locations, new_authors, main_info, secondary_info):
|
| 1244 |
-
|
| 1245 |
-
#Add Bluebeam-compatible count annotations
|
| 1246 |
-
annotated_pdf_bytes = add_bluebeam_count_annotations_secondary(input_pdf_path, locations, main_info, secondary_info)
|
| 1247 |
|
| 1248 |
-
#Modify author field using PyPDF2
|
| 1249 |
-
final_pdf_bytes = modify_author_in_pypdf2(annotated_pdf_bytes, new_authors)
|
| 1250 |
|
| 1251 |
-
return final_pdf_bytes
|
| 1252 |
|
| 1253 |
-
import fitz # PyMuPDF
|
| 1254 |
-
import PyPDF2
|
| 1255 |
-
import io
|
| 1256 |
-
from PyPDF2.generic import TextStringObject # ✅ Required for setting string values
|
| 1257 |
|
| 1258 |
-
'''def add_bluebeam_count_annotations(pdf_bytes, locations):
|
| 1259 |
-
pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
|
| 1260 |
-
pdf_document = fitz.open("pdf", pdf_stream.read()) # Open PDF in memory
|
| 1261 |
-
|
| 1262 |
-
page = pdf_document[0] # First page
|
| 1263 |
-
if len(locations[0]) == 3:
|
| 1264 |
-
for loc in locations:
|
| 1265 |
-
coor, lbl, clr = loc
|
| 1266 |
-
clr = (clr[0] / 255, clr[1] / 255, clr[2] / 255)
|
| 1267 |
-
for cor in coor:
|
| 1268 |
-
#Create a Circle annotation (Count Markup)
|
| 1269 |
-
annot = page.add_circle_annot(
|
| 1270 |
-
fitz.Rect(cor[0] - 10, cor[1] - 10, cor[0] + 10, cor[1] + 10) # Small circle
|
| 1271 |
-
)
|
| 1272 |
-
|
| 1273 |
-
#Assign required Bluebeam metadata
|
| 1274 |
-
annot.set_colors(stroke=clr, fill=(1, 1, 1)) # Set stroke color and fill white
|
| 1275 |
-
annot.set_border(width=2) # Border thickness
|
| 1276 |
-
annot.set_opacity(1) # Fully visible
|
| 1277 |
-
|
| 1278 |
-
#Set annotation properties for Bluebeam Count detection
|
| 1279 |
-
annot.set_info("name", lbl) # Unique name for each count
|
| 1280 |
-
annot.set_info("subject", "Count") #Bluebeam uses "Count" for Count markups
|
| 1281 |
-
annot.set_info("title", lbl) # Optional
|
| 1282 |
-
annot.update() # Apply changes
|
| 1283 |
-
if len(locations[0]) == 4:
|
| 1284 |
-
for loc in locations:
|
| 1285 |
-
coor, lbl, clr,w = loc
|
| 1286 |
-
clr = (clr[0] / 255, clr[1] / 255, clr[2] / 255)
|
| 1287 |
-
for cor in coor:
|
| 1288 |
-
#Create a Circle annotation (Count Markup)
|
| 1289 |
-
annot = page.add_circle_annot(
|
| 1290 |
-
fitz.Rect(cor[0] - 10, cor[1] - 10, cor[0] + 10, cor[1] + 10) # Small circle
|
| 1291 |
-
)
|
| 1292 |
-
|
| 1293 |
-
#Assign required Bluebeam metadata
|
| 1294 |
-
annot.set_colors(stroke=clr, fill=(1, 1, 1)) # Set stroke color and fill white
|
| 1295 |
-
annot.set_border(width=2) # Border thickness
|
| 1296 |
-
annot.set_opacity(1) # Fully visible
|
| 1297 |
-
|
| 1298 |
-
#Set annotation properties for Bluebeam Count detection
|
| 1299 |
-
annot.set_info("name", lbl) # Unique name for each count
|
| 1300 |
-
annot.set_info("subject", "Count") #Bluebeam uses "Count" for Count markups
|
| 1301 |
-
annot.set_info("title", lbl) # Optional
|
| 1302 |
-
annot.update() # Apply changes
|
| 1303 |
-
if len(locations[0]) == 5:
|
| 1304 |
-
for loc in locations:
|
| 1305 |
-
coor, lbl, clr,w,h = loc
|
| 1306 |
-
clr = (clr[0] / 255, clr[1] / 255, clr[2] / 255)
|
| 1307 |
-
for cor in coor:
|
| 1308 |
-
#Create a Circle annotation (Count Markup)
|
| 1309 |
-
annot = page.add_circle_annot(
|
| 1310 |
-
fitz.Rect(cor[0] - 10, cor[1] - 10, cor[0] + 10, cor[1] + 10) # Small circle
|
| 1311 |
-
)
|
| 1312 |
-
|
| 1313 |
-
#Assign required Bluebeam metadata
|
| 1314 |
-
annot.set_colors(stroke=clr, fill=(1, 1, 1)) # Set stroke color and fill white
|
| 1315 |
-
annot.set_border(width=2) # Border thickness
|
| 1316 |
-
annot.set_opacity(1) # Fully visible
|
| 1317 |
-
|
| 1318 |
-
#Set annotation properties for Bluebeam Count detection
|
| 1319 |
-
annot.set_info("name", lbl) # Unique name for each count
|
| 1320 |
-
annot.set_info("subject", "Count") #Bluebeam uses "Count" for Count markups
|
| 1321 |
-
annot.set_info("title", lbl) # Optional
|
| 1322 |
-
annot.update() # Apply changes
|
| 1323 |
-
|
| 1324 |
-
#Save modified PDF to a variable instead of a file
|
| 1325 |
-
output_stream = io.BytesIO()
|
| 1326 |
-
pdf_document.save(output_stream)
|
| 1327 |
-
pdf_document.close()
|
| 1328 |
-
|
| 1329 |
-
return output_stream.getvalue() # Return the modified PDF as bytes
|
| 1330 |
-
'''
|
| 1331 |
def add_bluebeam_count_annotations(pdf_bytes, locations):
|
| 1332 |
pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
|
| 1333 |
pdf_document = fitz.open("pdf", pdf_stream.read()) # Open PDF in memory
|
|
@@ -1404,11 +1039,6 @@ def add_bluebeam_count_annotations(pdf_bytes, locations):
|
|
| 1404 |
return output_stream.getvalue() # Return the modified PDF as bytes
|
| 1405 |
|
| 1406 |
|
| 1407 |
-
def get_user_input(user_words):
|
| 1408 |
-
user_input = []
|
| 1409 |
-
for item in user_words:
|
| 1410 |
-
user_input.append(item[0])
|
| 1411 |
-
return user_input
|
| 1412 |
|
| 1413 |
def modify_author_in_pypdf2(pdf_bytes, new_authors):
|
| 1414 |
pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
|
|
@@ -1441,9 +1071,7 @@ def modify_author_in_pypdf2(pdf_bytes, new_authors):
|
|
| 1441 |
|
| 1442 |
return output_stream.read()
|
| 1443 |
|
| 1444 |
-
# return output_stream.getvalue() # Return modified PDF as bytes
|
| 1445 |
|
| 1446 |
-
from PyPDF2 import PdfReader, PdfWriter
|
| 1447 |
|
| 1448 |
def merge_pdf_bytes_list(pdfs):
|
| 1449 |
writer = PdfWriter()
|
|
@@ -1460,20 +1088,6 @@ def merge_pdf_bytes_list(pdfs):
|
|
| 1460 |
|
| 1461 |
return output_stream.read()
|
| 1462 |
|
| 1463 |
-
def process_pdf(input_pdf_path, output_pdf_path, locations, new_authors):
|
| 1464 |
-
#Load original PDF
|
| 1465 |
-
# with open(input_pdf_path, "rb") as file:
|
| 1466 |
-
# original_pdf_bytes = file.read()
|
| 1467 |
-
|
| 1468 |
-
#Add Bluebeam-compatible count annotations
|
| 1469 |
-
annotated_pdf_bytes = add_bluebeam_count_annotations(input_pdf_path, locations)
|
| 1470 |
-
|
| 1471 |
-
#Modify author field using PyPDF2
|
| 1472 |
-
final_pdf_bytes = modify_author_in_pypdf2(annotated_pdf_bytes, new_authors)
|
| 1473 |
-
return final_pdf_bytes
|
| 1474 |
-
# #Save the final modified PDF to disk
|
| 1475 |
-
# with open(output_pdf_path, "wb") as file:
|
| 1476 |
-
# file.write(final_pdf_bytes)
|
| 1477 |
|
| 1478 |
def process_pdf_secondary(input_pdf_path, output_pdf_path, locations, new_authors, main_info, secondary_info):
|
| 1479 |
|
|
@@ -1506,6 +1120,7 @@ def process_pdf(input_pdf_path, output_pdf_path, locations, new_authors):
|
|
| 1506 |
#Modify author field using PyPDF2
|
| 1507 |
final_pdf_bytes = modify_author_in_pypdf2(annotated_pdf_bytes, new_authors)
|
| 1508 |
return final_pdf_bytes
|
|
|
|
| 1509 |
def mainRun(schedule, plan, searcharray):
|
| 1510 |
print("mainRun is RUNNING")
|
| 1511 |
|
|
|
|
| 13 |
from PyPDF2.generic import TextStringObject
|
| 14 |
import numpy as np
|
| 15 |
import cv2
|
| 16 |
+
from collections import defaultdict
|
| 17 |
+
import random
|
| 18 |
+
import fitz # PyMuPDF
|
| 19 |
+
import PyPDF2
|
| 20 |
+
import io
|
| 21 |
+
from PyPDF2.generic import TextStringObject # ✅ Required for setting string values
|
| 22 |
+
from PyPDF2 import PdfReader, PdfWriter
|
| 23 |
|
| 24 |
|
| 25 |
def convert2img(path):
|
|
|
|
| 399 |
return None
|
| 400 |
|
| 401 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
def find_text_in_plan(label, x):
|
| 403 |
substring_coordinates = []
|
| 404 |
words = []
|
|
|
|
| 411 |
words.append(tpl[4])
|
| 412 |
return substring_coordinates, words, point_list
|
| 413 |
|
| 414 |
+
|
| 415 |
+
|
| 416 |
def get_word_locations_plan(flattened_list, plan_texts):
|
| 417 |
locations = []
|
| 418 |
not_found = []
|
|
|
|
| 540 |
return widths
|
| 541 |
|
| 542 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
|
| 544 |
def get_width_info_tobeprinted_secondary(new_data, main_info, secondary_info):
|
| 545 |
width_info_tobeprinted = []
|
|
|
|
| 585 |
secondary_info_tobeprinted.append((acous, fire))
|
| 586 |
return width_info_tobeprinted, secondary_info_tobeprinted
|
| 587 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 588 |
|
| 589 |
def get_word_locations_plan_secondary(flattened_list, plan_texts, main_info, secondary_info):
|
| 590 |
#hena fe 7alet en keda keda fe secondary information
|
|
|
|
| 641 |
return locations, not_found
|
| 642 |
|
| 643 |
### newest, accept combined table
|
|
|
|
|
|
|
|
|
|
| 644 |
def get_similar_colors_all(selected_columns_new):
|
| 645 |
def generate_rgb():
|
| 646 |
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
|
|
|
| 759 |
|
| 760 |
return new_data
|
| 761 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 762 |
def get_secondary_tobeprinted_clean(selected_secondary_info, secondary_tobeprinted, secondary_info):
|
| 763 |
secondary_printed_clean = []
|
| 764 |
if len(secondary_info) == 1:
|
|
|
|
| 927 |
|
| 928 |
return output_stream.getvalue() # Return the modified PDF as bytes
|
| 929 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 930 |
|
| 931 |
def modify_author_in_pypdf2(pdf_bytes, new_authors):
|
| 932 |
pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
|
|
|
|
| 959 |
|
| 960 |
return output_stream.read()
|
| 961 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 962 |
|
|
|
|
|
|
|
| 963 |
|
|
|
|
| 964 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 965 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 966 |
def add_bluebeam_count_annotations(pdf_bytes, locations):
|
| 967 |
pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
|
| 968 |
pdf_document = fitz.open("pdf", pdf_stream.read()) # Open PDF in memory
|
|
|
|
| 1039 |
return output_stream.getvalue() # Return the modified PDF as bytes
|
| 1040 |
|
| 1041 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1042 |
|
| 1043 |
def modify_author_in_pypdf2(pdf_bytes, new_authors):
|
| 1044 |
pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
|
|
|
|
| 1071 |
|
| 1072 |
return output_stream.read()
|
| 1073 |
|
|
|
|
| 1074 |
|
|
|
|
| 1075 |
|
| 1076 |
def merge_pdf_bytes_list(pdfs):
|
| 1077 |
writer = PdfWriter()
|
|
|
|
| 1088 |
|
| 1089 |
return output_stream.read()
|
| 1090 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1091 |
|
| 1092 |
def process_pdf_secondary(input_pdf_path, output_pdf_path, locations, new_authors, main_info, secondary_info):
|
| 1093 |
|
|
|
|
| 1120 |
#Modify author field using PyPDF2
|
| 1121 |
final_pdf_bytes = modify_author_in_pypdf2(annotated_pdf_bytes, new_authors)
|
| 1122 |
return final_pdf_bytes
|
| 1123 |
+
|
| 1124 |
def mainRun(schedule, plan, searcharray):
|
| 1125 |
print("mainRun is RUNNING")
|
| 1126 |
|