Politrees commited on
Commit
19b4ae5
·
verified ·
1 Parent(s): 9ddb81a

Update steganography.py

Browse files
Files changed (1) hide show
  1. steganography.py +122 -62
steganography.py CHANGED
@@ -1,13 +1,15 @@
1
- import numpy as np
2
- import matplotlib.pyplot as plt
3
- from PIL import Image, ImageDraw, ImageFont
 
 
 
4
  import librosa
5
  import librosa.display
6
- import gradio as gr
 
7
  import soundfile as sf
8
- import os
9
- import logging
10
- import tempfile
11
 
12
  # Constants
13
  DEFAULT_FONT_PATH = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
@@ -16,38 +18,52 @@ DEFAULT_SAMPLE_RATE = 22050
16
  # Setup logging
17
  logging.basicConfig(level=logging.INFO)
18
 
 
19
  # Function for creating a spectrogram image with text
20
- def text_to_spectrogram_image(text, base_width=512, height=256, max_font_size=80, margin=10, letter_spacing=5):
 
 
21
  try:
22
  font = ImageFont.truetype(DEFAULT_FONT_PATH, max_font_size)
23
  except IOError:
24
  logging.warning(f"Font not found at {DEFAULT_FONT_PATH}. Using default font.")
25
  font = ImageFont.load_default()
26
-
27
- draw = ImageDraw.Draw(Image.new('L', (1, 1)))
28
-
29
- text_width = sum(draw.textbbox((0, 0), char, font=font)[2] - draw.textbbox((0, 0), char, font=font)[0] + letter_spacing for char in text) - letter_spacing
30
- text_height = draw.textbbox((0, 0), text[0], font=font)[3] - draw.textbbox((0, 0), text[0], font=font)[1]
 
 
 
 
 
 
 
 
 
 
31
 
32
  # Adjust width and height based on text size
33
  width = max(base_width, text_width + margin * 2)
34
  height = max(height, text_height + margin * 2)
35
 
36
- image = Image.new('L', (width, height), 'black')
37
  draw = ImageDraw.Draw(image)
38
 
39
- text_x = (width - text_width) // 2
40
- text_y = (height - text_height) // 2
41
 
42
- for char in text:
43
- draw.text((text_x, text_y), char, font=font, fill='white')
44
- char_bbox = draw.textbbox((0, 0), char, font=font)
45
- text_x += char_bbox[2] - char_bbox[0] + letter_spacing
46
 
47
  image = np.array(image)
48
  image = np.where(image > 0, 255, image)
49
  return image
50
 
 
51
  # Converting an image to audio
52
  def spectrogram_image_to_audio(image, sr=DEFAULT_SAMPLE_RATE):
53
  flipped_image = np.flipud(image)
@@ -55,30 +71,42 @@ def spectrogram_image_to_audio(image, sr=DEFAULT_SAMPLE_RATE):
55
  y = librosa.griffinlim(S)
56
  return y
57
 
 
58
  # Function for creating an audio file and spectrogram from text
59
- def create_audio_with_spectrogram(text, base_width, height, max_font_size, margin, letter_spacing):
60
- spec_image = text_to_spectrogram_image(text, base_width, height, max_font_size, margin, letter_spacing)
 
 
 
 
61
  y = spectrogram_image_to_audio(spec_image)
62
-
63
- with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_audio:
64
  audio_path = temp_audio.name
65
  sf.write(audio_path, y, DEFAULT_SAMPLE_RATE)
66
-
67
  # Create spectrogram from audio
68
  S = librosa.feature.melspectrogram(y=y, sr=DEFAULT_SAMPLE_RATE)
69
  S_dB = librosa.power_to_db(S, ref=np.max)
70
  plt.figure(figsize=(10, 4))
71
- librosa.display.specshow(S_dB, sr=DEFAULT_SAMPLE_RATE, x_axis='time', y_axis='mel')
72
- plt.axis('off')
73
  plt.tight_layout(pad=0)
74
-
75
- with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_spectrogram:
76
  spectrogram_path = temp_spectrogram.name
77
- plt.savefig(spectrogram_path, bbox_inches='tight', pad_inches=0, transparent=True)
 
 
78
  plt.close()
79
-
 
 
 
 
80
  return audio_path, spectrogram_path
81
 
 
82
  # Function for displaying the spectrogram of an audio file
83
  def display_audio_spectrogram(audio_path):
84
  y, sr = librosa.load(audio_path, sr=None)
@@ -86,80 +114,112 @@ def display_audio_spectrogram(audio_path):
86
  S_dB = librosa.power_to_db(S, ref=np.max)
87
 
88
  plt.figure(figsize=(10, 4))
89
- librosa.display.specshow(S_dB, sr=sr, x_axis='time', y_axis='mel')
90
- plt.axis('off')
91
  plt.tight_layout(pad=0)
92
 
93
- with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_spectrogram:
94
- spectrogram_path = temp_spectrogram.name
95
- plt.savefig(spectrogram_path, bbox_inches='tight', pad_inches=0, transparent=True)
96
  plt.close()
97
- return spectrogram_path
 
 
98
 
99
  # Converting a downloaded image to an audio spectrogram
100
  def image_to_spectrogram_audio(image_path, sr=DEFAULT_SAMPLE_RATE):
101
- image = Image.open(image_path).convert('L')
102
  image = np.array(image)
103
  y = spectrogram_image_to_audio(image, sr)
104
-
105
- with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_audio:
106
  img2audio_path = temp_audio.name
107
  sf.write(img2audio_path, y, sr)
108
  return img2audio_path
109
 
 
110
  # Gradio interface
111
- def gradio_interface_fn(text, base_width, height, max_font_size, margin, letter_spacing):
112
- logging.info(f"Generating audio and spectrogram for text:\n{text}\n")
113
- audio_path, spectrogram_path = create_audio_with_spectrogram(text, base_width, height, max_font_size, margin, letter_spacing)
 
 
 
114
  return audio_path, spectrogram_path
115
 
 
116
  def gradio_image_to_audio_fn(upload_image):
117
- logging.info(f"Converting image to audio:\n{upload_image}\n")
118
  return image_to_spectrogram_audio(upload_image)
119
 
 
120
  def gradio_decode_fn(upload_audio):
121
- logging.info(f"Generating spectrogram for audio:\n{upload_audio}\n")
122
  return display_audio_spectrogram(upload_audio)
123
 
124
- with gr.Blocks(title='Audio Steganography', css="footer{display:none !important}", theme=gr.themes.Soft(primary_hue="green", secondary_hue="green", spacing_size="sm", radius_size="lg")) as txt2spec:
 
 
 
 
 
 
 
125
  with gr.Tab("Text to Spectrogram"):
126
  with gr.Group():
127
- text = gr.Textbox(lines=2, placeholder="Enter your text:", label="Text")
128
- with gr.Row(variant='panel'):
129
  base_width = gr.Slider(value=512, label="Image Width", visible=False)
130
  height = gr.Slider(value=256, label="Image Height", visible=False)
131
- max_font_size = gr.Slider(minimum=10, maximum=130, step=5, value=80, label="Font size")
132
- margin = gr.Slider(minimum=0, maximum=50, step=1, value=10, label="Indent")
133
- letter_spacing = gr.Slider(minimum=0, maximum=50, step=1, value=5, label="Letter spacing")
134
- generate_button = gr.Button("Generate", variant='primary', size="lg")
135
-
136
- with gr.Column(variant='panel'):
 
 
 
 
 
 
137
  with gr.Group():
138
  output_audio = gr.Audio(type="filepath", label="Generated audio")
139
  output_spectrogram = gr.Image(type="filepath", label="Spectrogram")
140
 
141
- generate_button.click(gradio_interface_fn, inputs=[text, base_width, height, max_font_size, margin, letter_spacing], outputs=[output_audio, output_spectrogram])
 
 
 
 
142
 
143
  with gr.Tab("Image to Spectrogram"):
144
  with gr.Group():
145
  with gr.Column():
146
  upload_image = gr.Image(type="filepath", label="Upload image")
147
- convert_button = gr.Button("Convert to audio", variant='primary', size="lg")
 
 
148
 
149
- with gr.Column(variant='panel'):
150
  output_audio_from_image = gr.Audio(type="filepath", label="Generated audio")
151
 
152
- convert_button.click(gradio_image_to_audio_fn, inputs=[upload_image], outputs=[output_audio_from_image])
 
 
 
 
153
 
154
  with gr.Tab("Audio Spectrogram"):
155
  with gr.Group():
156
  with gr.Column():
157
  upload_audio = gr.Audio(type="filepath", label="Upload audio", scale=3)
158
- decode_button = gr.Button("Show spectrogram", variant='primary', size="lg")
 
 
159
 
160
- with gr.Column(variant='panel'):
161
  decoded_image = gr.Image(type="filepath", label="Audio Spectrogram")
162
 
163
- decode_button.click(gradio_decode_fn, inputs=[upload_audio], outputs=[decoded_image])
 
 
164
 
165
- txt2spec.launch(share=True)
 
1
+ import logging
2
+ import tempfile
3
+ import os
4
+ from io import BytesIO
5
+
6
+ import gradio as gr
7
  import librosa
8
  import librosa.display
9
+ import matplotlib.pyplot as plt
10
+ import numpy as np
11
  import soundfile as sf
12
+ from PIL import Image, ImageDraw, ImageFont
 
 
13
 
14
  # Constants
15
  DEFAULT_FONT_PATH = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
 
18
  # Setup logging
19
  logging.basicConfig(level=logging.INFO)
20
 
21
+
22
  # Function for creating a spectrogram image with text
23
+ def text_to_spectrogram_image(
24
+ text, base_width=512, height=256, max_font_size=80, margin=10, letter_spacing=5
25
+ ):
26
  try:
27
  font = ImageFont.truetype(DEFAULT_FONT_PATH, max_font_size)
28
  except IOError:
29
  logging.warning(f"Font not found at {DEFAULT_FONT_PATH}. Using default font.")
30
  font = ImageFont.load_default()
31
+ except Exception as e:
32
+ logging.error(f"An error occurred while loading the font: {e}")
33
+ raise
34
+
35
+ draw = ImageDraw.Draw(Image.new("L", (1, 1)))
36
+
37
+ text_widths = [
38
+ draw.textbbox((0, 0), char, font=font)[2] - draw.textbbox((0, 0), char, font=font)[0]
39
+ for char in text
40
+ ]
41
+ text_width = sum(text_widths) + letter_spacing * (len(text) - 1)
42
+ text_height = (
43
+ draw.textbbox((0, 0), text[0], font=font)[3]
44
+ - draw.textbbox((0, 0), text[0], font=font)[1]
45
+ )
46
 
47
  # Adjust width and height based on text size
48
  width = max(base_width, text_width + margin * 2)
49
  height = max(height, text_height + margin * 2)
50
 
51
+ image = Image.new("L", (width, height), "black")
52
  draw = ImageDraw.Draw(image)
53
 
54
+ text_start_x = (width - text_width) // 2
55
+ text_start_y = (height - text_height) // 2
56
 
57
+ current_x = text_start_x
58
+ for char, char_width in zip(text, text_widths):
59
+ draw.text((current_x, text_start_y), char, font=font, fill="white")
60
+ current_x += char_width + letter_spacing
61
 
62
  image = np.array(image)
63
  image = np.where(image > 0, 255, image)
64
  return image
65
 
66
+
67
  # Converting an image to audio
68
  def spectrogram_image_to_audio(image, sr=DEFAULT_SAMPLE_RATE):
69
  flipped_image = np.flipud(image)
 
71
  y = librosa.griffinlim(S)
72
  return y
73
 
74
+
75
  # Function for creating an audio file and spectrogram from text
76
+ def create_audio_with_spectrogram(
77
+ text, base_width, height, max_font_size, margin, letter_spacing
78
+ ):
79
+ spec_image = text_to_spectrogram_image(
80
+ text, base_width, height, max_font_size, margin, letter_spacing
81
+ )
82
  y = spectrogram_image_to_audio(spec_image)
83
+
84
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_audio:
85
  audio_path = temp_audio.name
86
  sf.write(audio_path, y, DEFAULT_SAMPLE_RATE)
87
+
88
  # Create spectrogram from audio
89
  S = librosa.feature.melspectrogram(y=y, sr=DEFAULT_SAMPLE_RATE)
90
  S_dB = librosa.power_to_db(S, ref=np.max)
91
  plt.figure(figsize=(10, 4))
92
+ librosa.display.specshow(S_dB, sr=DEFAULT_SAMPLE_RATE, x_axis="time", y_axis="mel")
93
+ plt.axis("off")
94
  plt.tight_layout(pad=0)
95
+
96
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_spectrogram:
97
  spectrogram_path = temp_spectrogram.name
98
+ plt.savefig(
99
+ spectrogram_path, bbox_inches="tight", pad_inches=0, transparent=True
100
+ )
101
  plt.close()
102
+
103
+ # Clean up temporary files
104
+ os.remove(audio_path)
105
+ os.remove(spectrogram_path)
106
+
107
  return audio_path, spectrogram_path
108
 
109
+
110
  # Function for displaying the spectrogram of an audio file
111
  def display_audio_spectrogram(audio_path):
112
  y, sr = librosa.load(audio_path, sr=None)
 
114
  S_dB = librosa.power_to_db(S, ref=np.max)
115
 
116
  plt.figure(figsize=(10, 4))
117
+ librosa.display.specshow(S_dB, sr=sr, x_axis="time", y_axis="mel")
118
+ plt.axis("off")
119
  plt.tight_layout(pad=0)
120
 
121
+ buf = BytesIO()
122
+ plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, transparent=True)
 
123
  plt.close()
124
+ buf.seek(0)
125
+ return buf
126
+
127
 
128
  # Converting a downloaded image to an audio spectrogram
129
  def image_to_spectrogram_audio(image_path, sr=DEFAULT_SAMPLE_RATE):
130
+ image = Image.open(image_path).convert("L")
131
  image = np.array(image)
132
  y = spectrogram_image_to_audio(image, sr)
133
+
134
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_audio:
135
  img2audio_path = temp_audio.name
136
  sf.write(img2audio_path, y, sr)
137
  return img2audio_path
138
 
139
+
140
  # Gradio interface
141
+ def gradio_interface_fn(
142
+ text, base_width, height, max_font_size, margin, letter_spacing
143
+ ):
144
+ audio_path, spectrogram_path = create_audio_with_spectrogram(
145
+ text, base_width, height, max_font_size, margin, letter_spacing
146
+ )
147
  return audio_path, spectrogram_path
148
 
149
+
150
  def gradio_image_to_audio_fn(upload_image):
 
151
  return image_to_spectrogram_audio(upload_image)
152
 
153
+
154
  def gradio_decode_fn(upload_audio):
 
155
  return display_audio_spectrogram(upload_audio)
156
 
157
+
158
+ with gr.Blocks(
159
+ title="Audio Steganography",
160
+ css="footer{display:none !important}",
161
+ theme=gr.themes.Soft(
162
+ primary_hue="green", secondary_hue="green", spacing_size="sm", radius_size="lg"
163
+ ),
164
+ ) as txt2spec:
165
  with gr.Tab("Text to Spectrogram"):
166
  with gr.Group():
167
+ text = gr.Textbox(lines=2, placeholder="Enter your text:", label="Text", info="Enter the text you want to convert to audio.")
168
+ with gr.Row(variant="panel"):
169
  base_width = gr.Slider(value=512, label="Image Width", visible=False)
170
  height = gr.Slider(value=256, label="Image Height", visible=False)
171
+ max_font_size = gr.Slider(
172
+ minimum=10, maximum=130, step=5, value=80, label="Font size"
173
+ )
174
+ margin = gr.Slider(
175
+ minimum=0, maximum=50, step=1, value=10, label="Indent"
176
+ )
177
+ letter_spacing = gr.Slider(
178
+ minimum=0, maximum=50, step=1, value=5, label="Letter spacing"
179
+ )
180
+ generate_button = gr.Button("Generate", variant="primary", size="lg")
181
+
182
+ with gr.Column(variant="panel"):
183
  with gr.Group():
184
  output_audio = gr.Audio(type="filepath", label="Generated audio")
185
  output_spectrogram = gr.Image(type="filepath", label="Spectrogram")
186
 
187
+ generate_button.click(
188
+ gradio_interface_fn,
189
+ inputs=[text, base_width, height, max_font_size, margin, letter_spacing],
190
+ outputs=[output_audio, output_spectrogram],
191
+ )
192
 
193
  with gr.Tab("Image to Spectrogram"):
194
  with gr.Group():
195
  with gr.Column():
196
  upload_image = gr.Image(type="filepath", label="Upload image")
197
+ convert_button = gr.Button(
198
+ "Convert to audio", variant="primary", size="lg"
199
+ )
200
 
201
+ with gr.Column(variant="panel"):
202
  output_audio_from_image = gr.Audio(type="filepath", label="Generated audio")
203
 
204
+ convert_button.click(
205
+ gradio_image_to_audio_fn,
206
+ inputs=[upload_image],
207
+ outputs=[output_audio_from_image],
208
+ )
209
 
210
  with gr.Tab("Audio Spectrogram"):
211
  with gr.Group():
212
  with gr.Column():
213
  upload_audio = gr.Audio(type="filepath", label="Upload audio", scale=3)
214
+ decode_button = gr.Button(
215
+ "Show spectrogram", variant="primary", size="lg"
216
+ )
217
 
218
+ with gr.Column(variant="panel"):
219
  decoded_image = gr.Image(type="filepath", label="Audio Spectrogram")
220
 
221
+ decode_button.click(
222
+ gradio_decode_fn, inputs=[upload_audio], outputs=[decoded_image]
223
+ )
224
 
225
+ txt2spec.launch(share=True)