diff --git a/public/images/logo.svg b/public/images/logo.svg
new file mode 100644
index 0000000..b6ec863
--- /dev/null
+++ b/public/images/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/utils/images/calculateFontSizeForText.ts b/src/utils/images/calculateFontSizeForText.ts
new file mode 100644
index 0000000..d96ad3b
--- /dev/null
+++ b/src/utils/images/calculateFontSizeForText.ts
@@ -0,0 +1,24 @@
+export function calculateFontSizeForText(text: string, maxWidth: number): number {
+ // Создаем временный элемент для измерения текста
+ const span = document.createElement('span')
+ span.style.position = 'absolute'
+ span.style.whiteSpace = 'nowrap'
+ span.style.fontFamily = 'Arial, sans-serif' // Задаем нужный шрифт
+ span.style.visibility = 'hidden'
+ span.textContent = text
+ document.body.appendChild(span)
+
+ // Начальный размер шрифта
+ let fontSize = maxWidth
+ span.style.fontSize = `${fontSize}px`
+
+ // Уменьшаем размер шрифта, пока ширина текста не впишется в maxWidth
+ while (span.offsetWidth > maxWidth) {
+ fontSize -= 1
+ span.style.fontSize = `${fontSize}px`
+ }
+
+ // Удаляем временный элемент
+ document.body.removeChild(span)
+ return fontSize
+}
diff --git a/src/utils/images/convertImageToBlob.ts b/src/utils/images/convertImageToBlob.ts
new file mode 100644
index 0000000..a49cd44
--- /dev/null
+++ b/src/utils/images/convertImageToBlob.ts
@@ -0,0 +1,58 @@
+export async function convertImageToBlob({
+ url,
+ width,
+ height,
+ type,
+}: {
+ url: string
+ width?: number // Ширина необязательна
+ height?: number // Высота необязательна
+ type: string
+}): Promise {
+ if (!width && !height) {
+ throw new Error('Необходимо указать хотя бы одно значение: width или height.')
+ }
+
+ return new Promise((resolve, reject) => {
+ const img = new Image()
+
+ img.onload = () => {
+ // Вычисляем размеры, сохраняя пропорции
+ const aspectRatio = img.naturalWidth / img.naturalHeight
+ const targetWidth = width || height! * aspectRatio
+ const targetHeight = height || width! / aspectRatio
+
+ // Создаем canvas и рисуем изображение
+ const canvas = document.createElement('canvas')
+ canvas.width = Math.round(targetWidth)
+ canvas.height = Math.round(targetHeight)
+ const context = canvas.getContext('2d')
+
+ if (!context) {
+ return reject(new Error('Ошибка создания контекста'))
+ }
+ context.drawImage(img, 0, 0, canvas.width, canvas.height)
+
+ // Конвертируем canvas в Blob
+ canvas.toBlob(
+ (blob) => {
+ if (blob) {
+ resolve(blob)
+ } else {
+ reject(new Error('Ошибка создания изображения'))
+ }
+ },
+ type,
+ 1.0,
+ )
+
+ URL.revokeObjectURL(url)
+ }
+
+ img.onerror = () => {
+ reject(new Error('Ошибка загрузки изображения'))
+ }
+
+ img.src = url
+ })
+}
diff --git a/src/utils/images/downloadImage.ts b/src/utils/images/downloadImage.ts
new file mode 100644
index 0000000..1cbd57c
--- /dev/null
+++ b/src/utils/images/downloadImage.ts
@@ -0,0 +1,28 @@
+import { convertImageToBlob } from './convertImageToBlob'
+
+export async function downloadImage({
+ url,
+ width,
+ height,
+ filename,
+ type,
+}: {
+ url: string
+ width?: number
+ height?: number
+ filename: string
+ type: string
+}) {
+ try {
+ const blob = await convertImageToBlob({ url, width, height, type })
+
+ const link = document.createElement('a')
+ link.href = URL.createObjectURL(blob)
+ link.download = filename
+ link.click()
+
+ URL.revokeObjectURL(link.href) // Очищаем URL после загрузки
+ } catch (err) {
+ console.error('Ошибка преобразования SVG в PNG:', err)
+ }
+}
diff --git a/src/views/ManageQRCodeReadyView.vue b/src/views/ManageQRCodeReadyView.vue
index 0285102..82e1400 100644
--- a/src/views/ManageQRCodeReadyView.vue
+++ b/src/views/ManageQRCodeReadyView.vue
@@ -60,14 +60,20 @@