deepak88 commited on
Commit
339cd6d
·
verified ·
1 Parent(s): 57fb7bc

Upload 7 files

Browse files
Files changed (8) hide show
  1. .gitattributes +2 -0
  2. app.py +355 -0
  3. arial.ttf +3 -0
  4. cour.ttf +3 -0
  5. crumple_texture.jpg +0 -0
  6. indian_oil_logo.png +0 -0
  7. requirements.txt +2 -0
  8. scan_texture.jpg +0 -0
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ arial.ttf filter=lfs diff=lfs merge=lfs -text
37
+ cour.ttf filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from PIL import Image, ImageDraw, ImageFont, ImageFilter
3
+ import random
4
+ import datetime
5
+ import io
6
+ import os
7
+
8
+ # --- Image Generation Function (Adapted for Gradio) ---
9
+ # This function will be called by Gradio, so its parameters need to match the Gradio inputs.
10
+ def generate_fuel_bill_image(
11
+ company_name: str,
12
+ company_address: str,
13
+ attendant_id: str,
14
+ vehicle_number: str,
15
+ mobile_number: str,
16
+ fuel_point_id: str,
17
+ nozzle_number: str,
18
+ fuel_type: str,
19
+ product: str,
20
+ density: str,
21
+ preset_type: str,
22
+ rate: float,
23
+ amount_option: str, # "random" or "manual"
24
+ manual_sale_amount: float,
25
+ min_rand_amount: float,
26
+ max_rand_amount: float,
27
+ image_width: int,
28
+ image_height: int,
29
+ font_size_input: int,
30
+ line_spacing_input: int,
31
+ margin_left_input: int,
32
+ logo_y_offset_input: int,
33
+ texture_opacity_input: float,
34
+ blur_radius_input: float,
35
+ selected_crumple_file_path: str, # path from gr.Dropdown or None
36
+ custom_crumple_file_obj, # tempfile object from gr.File
37
+ selected_logo_file_path: str, # path from gr.Dropdown or None
38
+ custom_logo_file_obj # tempfile object from gr.File
39
+ ) -> Image.Image: # Specify that the function returns a PIL Image
40
+
41
+ # Determine sale_amount based on selected option
42
+ sale_amount = manual_sale_amount
43
+ if amount_option == "random":
44
+ sale_amount = round(random.uniform(min_rand_amount, max_rand_amount), 2)
45
+
46
+ # --- Helper Functions (from your original code) ---
47
+ def generate_bill_number():
48
+ return f"{random.randint(100000, 999999)}-ORGNL"
49
+
50
+ def generate_transaction_id():
51
+ return f"{random.randint(1000000000000000, 9999999999999999):016d}"
52
+
53
+ def generate_random_datetime():
54
+ start_date = datetime.date(2024, 4, 1)
55
+ end_date = datetime.date.today() # Use today's date for end bound
56
+ time_between_dates = end_date - start_date
57
+ days_between_dates = time_between_dates.days
58
+ random_number_of_days = random.randrange(days_between_dates + 1)
59
+ random_date = start_date + datetime.timedelta(days=random_number_of_days)
60
+
61
+ random_hour = random.randint(8, 23)
62
+ random_minute = random.randint(0, 59)
63
+ random_second = random.randint(0, 59)
64
+
65
+ random_time = datetime.time(random_hour, random_minute, random_second)
66
+ return random_date.strftime("%d/%m/%Y"), random_time.strftime("%H:%M:%S")
67
+
68
+ def calculate_volume(rate_val, sale_amount_val):
69
+ try:
70
+ return round(float(sale_amount_val) / float(rate_val), 2)
71
+ except ZeroDivisionError:
72
+ return 0.0
73
+
74
+ # --- Core Generation Logic ---
75
+ bill_number = generate_bill_number()
76
+ transaction_id = generate_transaction_id()
77
+ date, time = generate_random_datetime()
78
+ volume = calculate_volume(rate, sale_amount)
79
+
80
+ # Use the passed input values for image dimensions and aesthetics
81
+ width = image_width
82
+ height = image_height
83
+ font_size = font_size_input
84
+ line_spacing = line_spacing_input
85
+ margin_left = margin_left_input
86
+ logo_y_offset = logo_y_offset_input
87
+ texture_opacity = texture_opacity_input
88
+ blur_radius = blur_radius_input
89
+
90
+ bg_color = (245, 245, 235)
91
+ text_color = (0, 0, 0)
92
+
93
+ # Define paths for assets (assuming they are in the same directory as app.py)
94
+ # Gradio will handle making these accessible
95
+ script_dir = os.path.dirname(__file__)
96
+ font_file = os.path.join(script_dir, "cour.ttf")
97
+ default_crumple_path = os.path.join(script_dir, "scan_texture.jpg")
98
+ default_logo_path = os.path.join(script_dir, "indian_oil_logo.png")
99
+
100
+ data = [
101
+ f"B111 No:{bill_number}",
102
+ f"Trns. ID:{transaction_id}",
103
+ f"Atnd. ID:{attendant_id if attendant_id else ''}",
104
+ f"Vehicle No:{vehicle_number}",
105
+ f"Mobile No: {mobile_number}",
106
+ f"Date :{date}",
107
+ f"Time :{time}",
108
+ f"FIP. ID :{fuel_point_id}",
109
+ f"Nozzle No:{nozzle_number}",
110
+ f"Fuel : {fuel_type}",
111
+ f"Prouct : {product}",
112
+ f"Density: {density}",
113
+ f"Preset Type : {preset_type}",
114
+ f"Rate :Rs. {rate:.2f}",
115
+ f"Sale :Rs.{sale_amount:.2f}",
116
+ f"Volume :{volume:.2f}",
117
+ "THANK YOU!",
118
+ "PLEASE VISIT AGAIN"
119
+ ]
120
+
121
+ # --- Crumple Texture ---
122
+ crumple = None
123
+ if custom_crumple_file_obj: # Custom uploaded file takes precedence
124
+ try:
125
+ crumple = Image.open(custom_crumple_file_obj.name).convert("RGB")
126
+ crumple = crumple.resize((width, height))
127
+ except Exception as e:
128
+ gr.Warning(f"Could not load custom background texture. Error: {e}. Using plain background.")
129
+ elif selected_crumple_file_path and selected_crumple_file_path != "None": # Selected default texture
130
+ try:
131
+ crumple = Image.open(selected_crumple_file_path).convert("RGB")
132
+ crumple = crumple.resize((width, height))
133
+ except FileNotFoundError:
134
+ gr.Warning(f"Selected default texture '{selected_crumple_file_path}' not found. Using plain background.")
135
+ except Exception as e:
136
+ gr.Warning(f"Error loading selected default texture: {e}. Using plain background.")
137
+ # else: crumple remains None, leading to a plain background
138
+
139
+ # --- Create base image ---
140
+ base_image = Image.new("RGB", (width, height), bg_color)
141
+ if crumple:
142
+ base_image = Image.blend(base_image, crumple, texture_opacity)
143
+
144
+ # --- Create a layer for the text and logo (transparent background) ---
145
+ text_layer = Image.new("RGBA", (width, height), (0, 0, 0, 0))
146
+ draw = ImageDraw.Draw(text_layer)
147
+
148
+ # --- Load font ---
149
+ try:
150
+ font = ImageFont.truetype(font_file, size=font_size)
151
+ except IOError:
152
+ gr.Warning(f"Font file '{font_file}' not found. Using default font.")
153
+ font = ImageFont.load_default()
154
+
155
+ # --- Load Logo ---
156
+ logo_height = 0
157
+ logo_max_width = width - (margin_left * 2) # Ensure logo fits within margins
158
+ if custom_logo_file_obj: # Custom uploaded logo takes precedence
159
+ try:
160
+ logo = Image.open(custom_logo_file_obj.name)
161
+ if logo.mode != 'RGBA':
162
+ logo = logo.convert("RGBA")
163
+
164
+ if logo.width > logo_max_width:
165
+ ratio = logo_max_width / logo.width
166
+ logo = logo.resize((int(logo.width * ratio), int(logo.height * ratio)))
167
+
168
+ logo_x = (width - logo.width) // 2
169
+ text_layer.paste(logo, (logo_x, logo_y_offset), logo)
170
+ logo_height = logo.height
171
+ except Exception as e:
172
+ gr.Warning(f"Could not load custom logo. Error: {e}. Proceeding without logo.")
173
+ elif selected_logo_file_path and selected_logo_file_path != "None": # Selected default logo
174
+ try:
175
+ logo = Image.open(selected_logo_file_path)
176
+ if logo.mode != 'RGBA':
177
+ logo = logo.convert("RGBA")
178
+
179
+ if logo.width > logo_max_width:
180
+ ratio = logo_max_width / logo.width
181
+ logo = logo.resize((int(logo.width * ratio), int(logo.height * ratio)))
182
+
183
+ logo_x = (width - logo.width) // 2
184
+ text_layer.paste(logo, (logo_x, logo_y_offset), logo)
185
+ logo_height = logo.height
186
+ except FileNotFoundError:
187
+ gr.Warning(f"Selected default logo '{selected_logo_file_path}' not found. Generating without logo.")
188
+ except Exception as e:
189
+ gr.Warning(f"Error loading selected default logo: {e}. Proceeding without logo.")
190
+
191
+ # --- Company Name and Address (Centered) ---
192
+ y_offset = logo_y_offset + logo_height + 20
193
+ company_address_lines = company_address.split('\n')
194
+ for line in company_address_lines:
195
+ company_name_width = draw.textlength(line, font=font)
196
+ draw.text(((width - company_name_width) // 2, y_offset), line, font=font, fill=text_color)
197
+ y_offset += line_spacing
198
+
199
+ y_offset += 20
200
+
201
+ # --- Transaction Data (Left-Aligned) ---
202
+ for line in data:
203
+ x_offset = margin_left
204
+ y_offset += line_spacing
205
+ draw.text((x_offset, y_offset), line, font=font, fill=text_color)
206
+
207
+ base_image = Image.alpha_composite(base_image.convert("RGBA"), text_layer)
208
+ base_image = base_image.filter(ImageFilter.GaussianBlur(radius=blur_radius))
209
+
210
+ return base_image.convert("RGB")
211
+
212
+ # --- Gradio Interface Layout ---
213
+
214
+ # Helper to get available default assets for Gradio dropdowns
215
+ def get_default_assets(extensions):
216
+ current_dir = os.path.dirname(__file__)
217
+ files = []
218
+ if os.path.exists(current_dir):
219
+ for f in os.listdir(current_dir):
220
+ if any(f.lower().endswith(ext) for ext in extensions):
221
+ files.append(os.path.join(current_dir, f)) # Return full path
222
+ return ["None"] + files
223
+
224
+ # Get paths to default textures and logos
225
+ default_texture_paths = get_default_assets([".jpg", ".jpeg", ".png"])
226
+ default_logo_paths = get_default_assets([".png", ".jpg", ".jpeg"])
227
+
228
+ with gr.Blocks(title="Fuel Bill Image Generator") as demo:
229
+ gr.Markdown(
230
+ """
231
+ # ⛽ Custom Fuel Bill Image Generator
232
+ Create realistic-looking fuel bill images with customizable details,
233
+ background textures, and your own logo!
234
+ """
235
+ )
236
+
237
+ with gr.Row():
238
+ with gr.Column(scale=1):
239
+ gr.Markdown("## ⚙️ Bill Details Customization")
240
+ gr.Markdown("### Company Information")
241
+ company_name_input = gr.Textbox(label="Company Name:", value="IndianOil")
242
+ company_address_input = gr.Textbox(
243
+ label="Company Address:",
244
+ value="Welcomes You\nM/S AAKASH BROTHERS\nVILL WAZIRABAD SEC 52\nGURUGRAM HR 122003\nTel . No.: 9311559777",
245
+ lines=5
246
+ )
247
+
248
+ gr.Markdown("### Transaction Information")
249
+ with gr.Row():
250
+ attendant_id_input = gr.Textbox(label="Attendant ID:", value="")
251
+ vehicle_number_input = gr.Textbox(label="Vehicle Number:", value="Not Entered")
252
+ with gr.Row():
253
+ mobile_number_input = gr.Textbox(label="Mobile Number:", value="Not Entered")
254
+ fuel_point_id_input = gr.Textbox(label="Fuel Point ID:", value="2")
255
+ with gr.Row():
256
+ nozzle_number_input = gr.Textbox(label="Nozzle Number:", value="2")
257
+ fuel_type_input = gr.Textbox(label="Fuel Type:", value="PETROL")
258
+ with gr.Row():
259
+ product_input = gr.Textbox(label="Product:", value="XP95")
260
+ density_input = gr.Textbox(label="Density:", value="778.1kg/m3")
261
+ preset_type_input = gr.Textbox(label="Preset Type:", value="Volume")
262
+
263
+ gr.Markdown("### Amount Details")
264
+ rate_input = gr.Number(label="Rate (Rs.):", value=102.07, step=0.01)
265
+
266
+ amount_option = gr.Radio(
267
+ choices=["Random", "Manual"],
268
+ value="Random",
269
+ label="Sale Amount Option:",
270
+ interactive=True
271
+ )
272
+
273
+ with gr.Column(visible=True) as random_amount_col:
274
+ min_rand_amount = gr.Number(label="Min Random Amount", value=2000.0, step=100.0)
275
+ max_rand_amount = gr.Number(label="Max Random Amount", value=5000.0, step=100.0)
276
+
277
+ with gr.Column(visible=False) as manual_amount_col:
278
+ manual_sale_amount = gr.Number(label="Manual Sale Amount (Rs.):", value=2500.00, step=0.01)
279
+
280
+ # Link visibility of columns to radio button
281
+ amount_option.change(
282
+ lambda value: (gr.Column.update(visible=value == "Random"), gr.Column.update(visible=value == "Manual")),
283
+ inputs=amount_option,
284
+ outputs=[random_amount_col, manual_amount_col]
285
+ )
286
+
287
+ gr.Markdown("## 🖼️ Background & Logo Selection")
288
+ gr.Markdown("### Background Texture")
289
+ selected_texture = gr.Dropdown(
290
+ label="Select a default texture:",
291
+ choices=default_texture_paths,
292
+ value=next((path for path in default_texture_paths if "scan_texture.jpg" in path), "None") # Pre-select if default exists
293
+ )
294
+ custom_crumple_file = gr.File(label="Or upload a custom background texture (PNG, JPG, JPEG)", type="filepath")
295
+
296
+ gr.Markdown("### Logo")
297
+ selected_logo = gr.Dropdown(
298
+ label="Select a default logo:",
299
+ choices=default_logo_paths,
300
+ value=next((path for path in default_logo_paths if "indian_oil_logo.png" in path), "None") # Pre-select if default exists
301
+ )
302
+ custom_logo_file = gr.File(label="Or upload a custom logo (PNG, JPG, JPEG)", type="filepath")
303
+
304
+ with gr.Column(scale=1):
305
+ gr.Markdown("## Image Aesthetics")
306
+ image_width = gr.Slider(label="Image Width", minimum=200, maximum=400, value=250, step=10)
307
+ image_height = gr.Slider(label="Image Height", minimum=500, maximum=900, value=700, step=10)
308
+ font_size_input = gr.Slider(label="Font Size", minimum=10, maximum=20, value=14, step=1)
309
+ line_spacing_input = gr.Slider(label="Line Spacing", minimum=15, maximum=25, value=18, step=1)
310
+ margin_left_input = gr.Slider(label="Left Margin", minimum=10, maximum=50, value=20, step=1)
311
+ logo_y_offset_input = gr.Slider(label="Logo Y-offset", minimum=0, maximum=100, value=20, step=5)
312
+ texture_opacity_input = gr.Slider(label="Texture Opacity", minimum=0.0, maximum=1.0, value=1.0, step=0.05)
313
+ blur_radius_input = gr.Slider(label="Blur Radius", minimum=0.0, maximum=1.0, value=0.2, step=0.05)
314
+
315
+ generate_button = gr.Button("Generate Fuel Bill Image")
316
+
317
+ gr.Markdown("## Generated Image:")
318
+ output_image = gr.Image(label="Your Custom Fuel Bill Image", type="pil")
319
+
320
+ generate_button.click(
321
+ fn=generate_fuel_bill_image,
322
+ inputs=[
323
+ company_name_input,
324
+ company_address_input,
325
+ attendant_id_input,
326
+ vehicle_number_input,
327
+ mobile_number_input,
328
+ fuel_point_id_input,
329
+ nozzle_number_input,
330
+ fuel_type_input,
331
+ product_input,
332
+ density_input,
333
+ preset_type_input,
334
+ rate_input,
335
+ amount_option, # Pass the radio button value
336
+ manual_sale_amount, # Pass the manual input field
337
+ min_rand_amount, # Pass min random amount
338
+ max_rand_amount, # Pass max random amount
339
+ image_width,
340
+ image_height,
341
+ font_size_input,
342
+ line_spacing_input,
343
+ margin_left_input,
344
+ logo_y_offset_input,
345
+ texture_opacity_input,
346
+ blur_radius_input,
347
+ selected_texture,
348
+ custom_crumple_file,
349
+ selected_logo,
350
+ custom_logo_file
351
+ ],
352
+ outputs=output_image
353
+ )
354
+
355
+ demo.launch()
arial.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:95766b58f7d869b0fa2cf6e6feb26c1b21cdf2631f1c5863fc9bd206d5c6e8ee
3
+ size 915212
cour.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:97c6ad2e60d7e41f34d3aa9e41fcc569ce64002d980d54cabc02e368393c3733
3
+ size 303296
crumple_texture.jpg ADDED
indian_oil_logo.png ADDED
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ streamlit
2
+ Pillow
scan_texture.jpg ADDED