├── .gitignore ├── README.md ├── assets ├── index.html └── my.js ├── java-diplom.iml ├── pics ├── debugger.jpg ├── idea-import-java.png ├── idea-import.jpg ├── packages.png ├── preview.png ├── simple-test-converted.png ├── simple-test-demo.jpeg └── simple-test.png └── src └── ru └── netology └── graphics ├── Main.java ├── image ├── BadImageSizeException.java ├── TextColorSchema.java └── TextGraphicsConverter.java └── server └── GServer.java /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | .idea 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Конвертер в текстовую графику Вас пригласили поучаствовать в разработке приложения, умеющего скачивать картинки по URL и конвертировать изображения в текстовую графику (т. е. в текст из разных символов, которые в совокупности выглядят как изображение). Вот пример его работы. Картинка на нём — это текст из мелких символов: ![](pics/preview.png) ## Скачиваем проект Часть приложения уже написана. Ваша задача — доработать его основную логическую часть в соответствии с требованиями. Поэтому для начала работы нужно скачать заготовку проекта. Для этого откройте идею, выберите в меню `File -> New -> Project from Version Control`. В открывшемся окне в поле URL введите `https://github.com/netology-code/java-diplom`, как показано на картинке, и нажмите Clone. ![](pics/idea-import.jpg) Если после нажатия выскочила ошибка об отсутствии гита на вашем компьютере, установите гит [по этой инструкции](https://github.com/netology-code/guides/tree/master/git) и попробуйте снова. После того как идея скачает проект, убедитесь, что для него выбрана версия Java. Откройте `File -> Project structure` и убедитесь, что это так. Версия должна быть 11-й. ![](pics/idea-import-java.png) После откройте класс `Main` и запустите метод `main`. Запуск должен завершиться ошибкой: ``` Exception in thread "main" java.lang.IllegalArgumentException: Серверу нужно передать в конструктор объект-конвертер, а было передано null. at ru.netology.graphics.server.GServer.(GServer.java:24) at ru.netology.graphics.Main.main(Main.java:13) ``` Если вы видите эту ошибку, проект настроен верно. Если нет, напишите своему руководителю по курсовой, он подскажет с настройкой. ## Структура проекта Перед вами java-проект с несколькими незнакомыми вам папками (например, `assets`), которые вам не нужно будет трогать. Нас будут интересовать .java-файлы, которые располагаются по пакетам: ![](pics/packages.png) | Класс / Интерфейс | Для чего? | | ----------- | ----------- | | `BadImageSizeException` | Класс исключения, которое вы будете выбрасывать | | `TextColorSchema` | Интерфейс цветовой схемы, который вы будете реализовывать | | `TextGraphicsConverter` | Интерфейс конвертера картинок, который вы будете реализовывать | | `GServer` | Готовый класс сервера, который будет использовать ваш конвертер; вам туда не нужно | | `Main` | Запуск приложения. В нём запускается сервер, также в нём можно будет конвертировать картинки в текстовые файлы без сервера | ## Требования к конвертеру В проекте уже написан класс сервера, который будет использовать ваш конвертер. Т. к. конвертер ещё не написан, был создан специальный интерфейс `TextGraphicsConverter`, объект которого сервер ждёт параметром в `Main`: ```java TextGraphicsConverter converter = null; // Создайте тут объект вашего класса конвертера GServer server = new GServer(converter); // Создаём объект сервера server.start(); // Запускаем ``` Все требования к конвертеру [описаны](src/ru/netology/graphics/image/TextGraphicsConverter.java) в интерфейсе. Чуть ниже мы их подробнее разберём. Самый главный метод — это метод `convert`, который принимает параметром URL в виде текста, например, `«https://raw.githubusercontent.com/netology-code/java-diplom/main/pics/simple-test.png»`, внутри метода качает и анализирует картинку, после чего отдаёт значение типа `String`, в котором содержится это изображение в виде текстовой графики. Помните, что в Java `String` — это текст и не обязательно всего одна строчка текста. Т. е. в один объект типа `String` можно занести многострочный текст, а разделителем строк (по сути Enter) будет специальный символ, который пишется в коде как `\n`. В итоге у вас в конце каждой строчки текстового изображения будет символ переноса строки (запись в коде — `\n`). Пример работы конвертера, результат которого выводим в консоль: ```java String url = "https://raw.githubusercontent.com/netology-code/java-diplom/main/pics/simple-test.png"; String imgTxt = converter.convert(url); System.out.println(imgTxt); ``` В итоге мы видим такой результат, где более тёмные участки заменяются на более жирные символы, а светлые на более незаметные символы: ![](pics/simple-test-demo.jpeg) Также интерфейс конвертера требует от него возможность выставлять ему настройки перед конвертацией: - максимально допустимое соотношение сторон (ширины и высоты). Если метод не вызывали, то любое соотношение допустимо; - максимально допустимую высоту итогового изображения. Если метод не вызывали, то любая высота допустима; - максимально допустимую ширину итогового изображения. Если метод не вызывали, то любая ширина допустима; - текстовую цветовую схему — объект специального интерфейса, который будет отвечать за превращение степени белого (числа от 0 до 255) в символ. Если метод не вызывали, должен использоваться объект написанного вами класса как значение по умолчанию. Например, следующий конвертер не должен конвертировать, если ширина больше длины в три раза, т. к. максимальное соотношение сторон ему выставлено в 2: ```java TextGraphicsConverter converter = ...; // Создайте тут объект вашего класса конвертера converter.setMaxRatio(2); // выставляет максимально допустимое соотрношение сторон картинки String imgTxt = converter.convert(...); // для слишком широкой картинки должно выброситься исключение BadImageSizeException. ``` Будьте внимательны: когда вы передадите конвертер серверу, он выставит ему свои желаемые параметры, которые будут влиять на конвертацию: ![image](https://user-images.githubusercontent.com/53707586/178140398-a07f6c63-6049-465d-9330-fe01efb659b2.png) При этом использовать при реализации конвертера информацию об этих конкретных числах нельзя. Ваш конвертер должен уметь работать с любыми настройками, описанными выше. Т. е. если в сервере поменяют настройки конвертеру, ваш конвертер без изменений кода должен работать с новыми значениями. Общая схема работы метода `convert` будет соответствовать последовательности действий (подробнее описаны ниже): 1. Скачиваем картинку по URL. 2. Менеджеру могли выставить максимально допустимое соотношение сторон (ширины и высоты); если оно слишком большое, то конвертация не делается и выбрасывается исключение. 3. При конвертации мы будем менять каждый пиксель на символ: чем пиксель темнее, тем жирнее символ, который мы подставим. Менеджеру могли выставить максимальные ширину и высоту итоговой картинки, при этом если исходная картинка больше, то нам надо уменьшить её размер, соблюдая пропорции. 4. Превращаем цветное изображение в чёрно-белое, чтобы мы смотрели только на интенсивность цвета, а не подбирали для красного одни символы, для зелёного другие и т. п. 1. Перебираем все пиксели изображения, спрашивая у них степень белого (число от 0 до 255, где 0 — это чёрный, а 255 — это светлый). В зависимости от этого числа выбираем символ из заранее подготовленного набора. 1. Собираем все полученные символы в единую строку, отдаём как результат конвертации. Костяк метода `convert`: ```java @Override public String convert(String url) throws IOException, BadImageSizeException { // Вот так просто мы скачаем картинку из интернета :) BufferedImage img = ImageIO.read(new URL(url)); // Если конвертер попросили проверять на максимально допустимое // соотношение сторон изображения, то вам здесь нужно сделать эту проверку, // и, если картинка не подходит, выбросить исключение BadImageSizeException. // Чтобы получить ширину картинки, вызовите img.getWidth(), высоту - img.getHeight() // Если конвертеру выставили максимально допустимые ширину и/или высоту, // вам нужно по ним и по текущим высоте и ширине вычислить новые высоту // и ширину. // Соблюдение пропорций означает, что вы должны уменьшать ширину и высоту // в одинаковое количество раз. // Пример 1: макс. допустимые 100x100, а картинка 500x200. Новый размер // будет 100x40 (в 5 раз меньше). // Пример 2: макс. допустимые 100x30, а картинка 150x15. Новый размер // будет 100x10 (в 1.5 раза меньше). // Подумайте, какими действиями можно вычислить новые размеры. // Не получается? Спросите вашего руководителя по курсовой, поможем. int newWidth = ???; int newHeight = ???; // Теперь нам нужно попросить картинку изменить свои размеры на новые. // Последний параметр означает, что мы просим картинку плавно сузиться // на новые размеры. В результате мы получаем ссылку на новую картинку, которая // представляет собой суженную старую. Image scaledImage = img.getScaledInstance(newWidth, newHeight, BufferedImage.SCALE_SMOOTH); // Теперь сделаем её чёрно-белой. Для этого поступим так: // Создадим новую пустую картинку нужных размеров, заранее указав последним // параметром чёрно-белую цветовую палитру: BufferedImage bwImg = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_BYTE_GRAY); // Попросим у этой картинки инструмент для рисования на ней: Graphics2D graphics = bwImg.createGraphics(); // А этому инструменту скажем, чтобы он скопировал содержимое из нашей суженной картинки: graphics.drawImage(scaledImage, 0, 0, null); // Теперь в bwImg у нас лежит чёрно-белая картинка нужных нам размеров. // Вы можете отслеживать каждый из этапов, в любом удобном для // вас моменте сохранив промежуточную картинку в файл через: // ImageIO.write(imageObject, "png", new File("out.png")); // После вызова этой инструкции у вас в проекте появится файл картинки out.png // Теперь давайте пройдёмся по пикселям нашего изображения. // Если для рисования мы просили у картинки .createGraphics(), // то для прохода по пикселям нам нужен будет этот инструмент: WritableRaster bwRaster = bwImg.getRaster(); // Он хорош тем, что у него мы можем спросить пиксель на нужных // нам координатах, указав номер столбца (w) и строки (h) // int color = bwRaster.getPixel(w, h, new int[3])[0]; // Выглядит странно? Согласен. Сам возвращаемый методом пиксель — это // массив из трёх интов, обычно это интенсивность красного, зелёного и синего. // Но у нашей чёрно-белой картинки цветов нет, и нас интересует // только первое значение в массиве. Ещё мы параметром передаём интовый массив на три ячейки. // Дело в том, что этот метод не хочет создавать его сам и просит // вас сделать это, а сам метод лишь заполнит его и вернёт. // Потому что создавать массивы каждый раз слишком медленно. Вы можете создать // массив один раз, сохранить в переменную и передавать один // и тот же массив в метод, ускорив тем самым программу. // Вам осталось пробежаться двойным циклом по всем столбцам (ширина) // и строкам (высота) изображения, на каждой внутренней итерации // получить степень белого пикселя (int color выше) и по ней // получить соответствующий символ c. Логикой превращения цвета // в символ будет заниматься другой объект, который мы рассмотрим ниже for ??? { for ??? { int color = bwRaster.getPixel(w, h, new int[3])[0]; char c = schema.convert(color); ??? //запоминаем символ c, например, в двумерном массиве или как-то ещё на ваше усмотрение } } // Осталось собрать все символы в один большой текст. // Для того, чтобы изображение не было слишком узким, рекомендую // каждый пиксель превращать в два повторяющихся символа, полученных // от схемы. return ???; // Возвращаем собранный текст. } ``` ## Требования к цветовой схеме Мы написали интерфейс конвертера так, чтобы сам он не подбирал каждому цвету определённый символ, но чтобы им занимался другой объект следующего интерфейса: ```java public interface TextColorSchema { char convert(int color); } ``` Предлагается следующая логика его работы. Вот список символов от самых тёмных к самым светлым: '▇', '●', '◉', '◍', '◎', '○', '☉', '◌', '-'. Если вы программируете на Windows, рекомендуем другой список из более стандартных символов, иначе может отрисовываться криво: '#', '$', '@', '%', '*', '+', '-', '\''. В зависимости от переданного значения интенсивности белого должен выбираться соответствующий символ. Например, если значение близко к 0, то выбрать надо '▇'; если к 255, то '-'. Если где-то посередине, то и выбирать надо тоже где-то посередине. Подумайте, как это можно реализовать. Вы можете сделать это условными операторами, однако есть и решение в одну строчку. Если у вас совсем не получается придумать, как это сделать, спросите вашего руководителя по курсовой. В итоге у вас должен быть класс, реализующий этот интерфейс. Если объекту конвертера сеттером не передали иную реализацию этого интерфейса, он должен использовать ваш класс как реализацию по умолчанию. **Внимание:** Все ваши новые классы должны быть в пакете `ru.netology.graphics.image`, никакие другие классы, кроме класса `Main`, менять нельзя. ## Тестирование, отладка и решение проблем После того как вы реализуете классы, откройте класс `Main` и заполните переменную для конвертера объектом вашего класса, чтобы он был передан серверу. Теперь после старта метода `main` будет запущен сервер на строке `server.start()`. Сервер будет писать о происходящем в консоль. Если ему удалось успешно стартовать, страница приложения будет доступна по локальному для вашего компьютера адресу http://localhost:8888/ . Для конвертации достаточно вставить прямую ссылку на картинку в форму и нажать `Convert`. Если конвертация будет успешной, перед вами будет изображение, выполненное текстовой графикой. Его сервер получит от вашего конвертера. Если конвертер не сможет сконвертировать, то в консоли будет стек-трейс исключения, однако сервер при этом не упадёт, а продолжит работу. На веб-странице будет сообщение о том, что конвертация не удалась. Для тестирования можете использовать URL следующих изображений: * Простое маленькое изображение для отладки: `https://raw.githubusercontent.com/netology-code/java-diplom/main/pics/simple-test.png` * Другое изображение для демонстрации: `https://i.ibb.co/6DYM05G/edu0.jpg` Во время поиска проблем вы также можете в `Main` закомментировать секцию, запускающую сервер, и раскомментировать логику, выводящую сконвертированное изображение в консоль. Также вы можете воспользоваться отладчиком: ![](pics/debugger.jpg) ## С чего начать Вы сами выбираете, с чего вам легче начать. Ниже представлен один из таких вариантов: 1. Начните реализацию с класса цветовой схемы. Создайте в пакете `ru.netology.graphics.image` класс, имплементирующий интерфейс `TextColorSchema`. 2. Реализуйте в нём метод конвертации цвета в символ, согласно требованиям к цветовой схеме, которые изложены выше. 3. Проверьте вашу цветовую схему. Создайте в `Main` её объект и попробуйте вызвать её метод. Правда ли, что на цветах ближе к белому будут более светлые символы и наоборот? Если это не так, проверьте работу отладчиком. 4. Приступите к реализации класса конвертера. Создайте в пакете `ru.netology.graphics.image` класс, имплементирующий интерфейс `TextGraphicsConverter`. 5. Сначала реализуйте просто метод convert, не обращая внимания на дополнительные требования: проверка картинки на макс. размеры и т. д. 6. Создайте объект конвертера и передайте его серверу в `main` или протестируйте в текстовом режиме, как было описано выше. Если вы сразу не реализовывали функции масштабирования картинки, то тестируйте только на небольших картинках. 7. Если конвертация работает, приступайте к реализации настроек конвертера — логики с проверкой на максимальное соотношение сторон, масштабирование картинки и т. д. Реализуйте функциональность по одной за раз, добиваясь работспособности вашего конвертера после каждой волны изменений. При возникновении трудностей пользуйтесь отладчиком. 8. Перечитайте условие — все ли требования выполнены? Протестируйте конвертер на разных картинках — работает ли? Если всё хорошо, ознакомьтесь с разделом «Как сдавать» и приступайте к отправке работы на проверку. ## Как сдавать Перед отправкой работы верните класс `Main` в [исходное состояние](src/ru/netology/graphics/Main.java), добавив только создание конвертера, т. е. оставьте режим с запуском сервера. Все ваши _новые_ классы должны быть в пакете `ru.netology.graphics.image`, никакие другие классы, кроме класса `Main`, менять нельзя. При отправке прикрепите файл `Main.java` и все созданные вами .java-файлы. Другие файлы прикреплять не нужно, также не стоит объединять все файлы в один архив, скидывать ссылку на репозиторий, реплит и прочее. -------------------------------------------------------------------------------- /assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Картинки → Текст 12 | 13 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |
23 | Урл картинки: 24 | 31 |
32 |
33 |
34 | 37 |
38 |
39 |
40 |
41 |
42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 56 | 57 | -------------------------------------------------------------------------------- /assets/my.js: -------------------------------------------------------------------------------- 1 | async function submit() { 2 | setLoading(true); 3 | const url = document.getElementById("img-url").value; 4 | if (!url) { 5 | error("Урл не может быть пустым!") 6 | return; 7 | } 8 | try { 9 | const resp = await fetch('/convert', { 10 | method: "POST", 11 | body: url 12 | }); 13 | if (!resp.ok) { 14 | error("Не могу сконвертировать :'(") 15 | return; 16 | } 17 | const txtImgRaw = await resp.text(); 18 | console.log(txtImgRaw.split("\n").length); 19 | const txtImgCleaned = txtImgRaw.replaceAll("\n", "
"); 20 | console.log(txtImgCleaned.split("
").length); 21 | console.log(txtImgCleaned) 22 | document.getElementById("txtimg").innerHTML = txtImgCleaned; 23 | succ("Ваше изображение сконвертировано!"); 24 | } catch (e) { 25 | error("Не могу сконвертировать :'(") 26 | } 27 | } 28 | 29 | function clearStatus() { 30 | document.getElementById("alert").innerHTML = ""; 31 | } 32 | 33 | function status(msg, type) { 34 | document.getElementById("alert").innerHTML = ` 35 | 38 | `; 39 | } 40 | 41 | function warn(msg) { 42 | status(msg, "warning"); 43 | } 44 | 45 | function succ(msg) { 46 | status(msg, "success"); 47 | } 48 | 49 | function info(msg) { 50 | status(msg, "info"); 51 | } 52 | 53 | function error(msg) { 54 | status(msg, "danger"); 55 | } 56 | 57 | function setLoading(isLoading) { 58 | if (isLoading) { 59 | const spinner = ` 60 |
61 | Loading... 62 |
`; 63 | status(spinner, "info"); 64 | } else { 65 | clearStatus(); 66 | } 67 | } -------------------------------------------------------------------------------- /java-diplom.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pics/debugger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/debugger.jpg -------------------------------------------------------------------------------- /pics/idea-import-java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/idea-import-java.png -------------------------------------------------------------------------------- /pics/idea-import.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/idea-import.jpg -------------------------------------------------------------------------------- /pics/packages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/packages.png -------------------------------------------------------------------------------- /pics/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/preview.png -------------------------------------------------------------------------------- /pics/simple-test-converted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/simple-test-converted.png -------------------------------------------------------------------------------- /pics/simple-test-demo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/simple-test-demo.jpeg -------------------------------------------------------------------------------- /pics/simple-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netology-code/java-diplom/5a3c9e57bd67fb41a4ad8ac5db30a74078275ca1/pics/simple-test.png -------------------------------------------------------------------------------- /src/ru/netology/graphics/Main.java: -------------------------------------------------------------------------------- 1 | package ru.netology.graphics; 2 | 3 | import ru.netology.graphics.image.TextGraphicsConverter; 4 | import ru.netology.graphics.server.GServer; 5 | 6 | import java.io.File; 7 | import java.io.PrintWriter; 8 | 9 | public class Main { 10 | public static void main(String[] args) throws Exception { 11 | TextGraphicsConverter converter = null; // Создайте тут объект вашего класса конвертера 12 | 13 | GServer server = new GServer(converter); // Создаём объект сервера 14 | server.start(); // Запускаем 15 | 16 | // Или то же, но с выводом на экран: 17 | //String url = "https://raw.githubusercontent.com/netology-code/java-diplom/main/pics/simple-test.png"; 18 | //String imgTxt = converter.convert(url); 19 | //System.out.println(imgTxt); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ru/netology/graphics/image/BadImageSizeException.java: -------------------------------------------------------------------------------- 1 | package ru.netology.graphics.image; 2 | 3 | public class BadImageSizeException extends Exception { 4 | public BadImageSizeException(double ratio, double maxRatio) { 5 | super("Максимальное соотношение сторон изображения " + maxRatio + ", а у этой " + ratio); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ru/netology/graphics/image/TextColorSchema.java: -------------------------------------------------------------------------------- 1 | package ru.netology.graphics.image; 2 | 3 | public interface TextColorSchema { 4 | char convert(int color); 5 | } 6 | -------------------------------------------------------------------------------- /src/ru/netology/graphics/image/TextGraphicsConverter.java: -------------------------------------------------------------------------------- 1 | package ru.netology.graphics.image; 2 | 3 | import java.io.IOException; 4 | import java.net.MalformedURLException; 5 | 6 | public interface TextGraphicsConverter { 7 | /** 8 | * Конвертация изображения, переданного как урл, в текстовую графику. 9 | * @param url урл изображения 10 | * @return текст, представляющий собой текстовую графику переданного изображения 11 | * @throws IOException 12 | * @throws BadImageSizeException Если соотношение сторон изображения слишком большое 13 | */ 14 | String convert(String url) throws IOException, BadImageSizeException; 15 | 16 | /** 17 | * Устанавливает максимальную ширину результирующего изображения в "текстовых пикселях". 18 | * Если исходное изображение имеет характеристики, превышающие максимальные, оно сжимается 19 | * с сохранением пропорций. 20 | * @param width максимальная ширина текстовых картинок 21 | */ 22 | void setMaxWidth(int width); 23 | 24 | /** 25 | * Устанавливает максимальную высоту результирующего изображения в "текстовых пикселях". 26 | * Если исходное изображение имеет характеристики, превышающие максимальные, оно сжимается 27 | * с сохранением пропорций. 28 | * @param height максимальная высоту текстовых картинок 29 | */ 30 | void setMaxHeight(int height); 31 | 32 | /** 33 | * Устанавливает максимально допустимое соотношение сторон исходного изображения. 34 | * Если исходное изображение имеет характеристики, превышающие максимальные, 35 | * при конвертации выбрасывается исключение. 36 | * @param maxRatio 37 | */ 38 | void setMaxRatio(double maxRatio); 39 | 40 | /** 41 | * Устанавливает символьную цветовую схему, которую будет использовать конвертер 42 | * @param schema 43 | */ 44 | void setTextColorSchema(TextColorSchema schema); 45 | } 46 | -------------------------------------------------------------------------------- /src/ru/netology/graphics/server/GServer.java: -------------------------------------------------------------------------------- 1 | package ru.netology.graphics.server; 2 | 3 | import com.sun.net.httpserver.HttpExchange; 4 | import com.sun.net.httpserver.HttpServer; 5 | import ru.netology.graphics.image.TextGraphicsConverter; 6 | 7 | import java.io.*; 8 | import java.net.InetSocketAddress; 9 | import java.net.http.HttpResponse; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | 13 | /** 14 | * Сервер уже за вас написан, его трогать не надо :) 15 | */ 16 | public class GServer { 17 | public static final int PORT = 8888; 18 | 19 | private HttpServer server; 20 | private TextGraphicsConverter converter; 21 | 22 | public GServer(TextGraphicsConverter converter) throws Exception { 23 | if (converter == null) { 24 | throw new IllegalArgumentException("Серверу нужно передать в конструктор объект-конвертер, а было передано null."); 25 | } 26 | this.converter = converter; 27 | this.converter.setMaxHeight(300); 28 | this.converter.setMaxWidth(300); 29 | this.converter.setMaxRatio(4); 30 | 31 | server = HttpServer.create(new InetSocketAddress("localhost", PORT), 0); 32 | server.createContext("/", this::serveHtml); 33 | server.createContext("/convert", this::serveConvertion); 34 | } 35 | 36 | public void start() { 37 | System.out.println("Запускаем сервер на порту " + PORT); 38 | System.out.println("Открой в браузере http://localhost:8888/"); 39 | server.start(); 40 | } 41 | 42 | protected void serveHtml(HttpExchange h) throws IOException { 43 | System.out.println("Serving html.."); 44 | var htmlPath = Path.of("assets/index.html"); 45 | var htmlContent = Files.readString(htmlPath); 46 | var jsPath = Path.of("assets/my.js"); 47 | var jsContent = Files.readString(jsPath); 48 | htmlContent = htmlContent.replace("{{{JS}}}", jsContent); 49 | var htmlBytes = htmlContent.getBytes(); 50 | h.sendResponseHeaders(200, htmlBytes.length); 51 | h.getResponseBody().write(htmlBytes); 52 | h.close(); 53 | } 54 | 55 | protected void serveConvertion(HttpExchange h) throws IOException { 56 | System.out.println("Convert request.."); 57 | var url = new BufferedReader(new InputStreamReader(h.getRequestBody())).readLine(); 58 | try { 59 | System.out.println("Converting image: " + url); 60 | Files.write(Path.of("assets/img.txt"), converter.convert(url).getBytes()); 61 | var img = converter.convert(url).getBytes(); 62 | System.out.println("...converted!"); 63 | h.sendResponseHeaders(200, img.length); 64 | h.getResponseBody().write(img); 65 | } catch (Exception e) { 66 | e.printStackTrace(); 67 | var msg = e.getMessage(); 68 | if (msg.isEmpty()) { 69 | msg = "Произошла ошибка конвертации :'("; 70 | } 71 | var msgBytes = msg.getBytes(); 72 | h.sendResponseHeaders(500, msgBytes.length); 73 | h.getResponseBody().write(msgBytes); 74 | } finally { 75 | h.close(); 76 | } 77 | } 78 | } 79 | --------------------------------------------------------------------------------