- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Написание скриптов для Blender 2.49 - Michel Anders
Шрифт:
Интервал:
Закладка:
Конечно, никакой из методов не является абсолютно надёжным, и несомненно, вопросы Captcha не лишены недостатков, они не будут устойчивыми при доступных больших компьютерных мощностях, но они все еще остаются весьма эффективными. Хотя в настоящее время считается, что способы с простым размытием и окраской — задачи решенные, компьютерам все еще требуется серьёзное время на разделение индивидуальных символов в слове, когда они слегка перекрывают друг друга, в то время как для людей это не проблема.
Учитывая эти аргументы, это может быть отличным применением рендеринга текста в 3D, так как, предположительно, трехмерное представление слов при подходящих условиях освещения (то есть, резкие тени) даже труднее для интерпретации, чем двумерный текст. Наша задача тогда заключается в разработке сервера, который будет отвечать на запросы, чтобы сделать трехмерное изображение какого-нибудь текста.
Мы разработаем наш сервер как веб-сервер, который будет реагировать на запросы, адресованные ему как URL'ы в форме http:<hostname>:<port>/captcha?text=<sometext>, и который возвращает PNG-изображение - 3D-представление этого текста. Таким образом, будет легко внедрить этот сервер в архитектуру, в которой некоторое программное обеспечение, например блог, может легко использовать эту функциональность, просто подключаясь к нашему серверу через HTTP. Пример сгенерированного вопроса показан на иллюстрации:
Разработка сервера CAPTCHAПри использовании модулей, доступных в полном дистрибутиве Питона, задача создания сервера HTTP становится не такой уж пугающей, как может показаться. Наш сервер Captcha будет основан на классах, предоставленных модулем Питона BaseHTTPServer, так что мы начинаем с импорта этого модуля вместе с несколькими дополнительными модулями-утилитами:
import BaseHTTPServer
import re
import os
import shutil
Модуль BaseHTTPServer определяет два класса, которые вместе включают полную реализацию сервера HTTP. Класс BaseHTTPServer реализует основной сервер, который будет слушать поступающие HTTP-запросы на некотором сетевом порту, и мы используем этот класс, как есть.
При получении корректного HTTP-запроса BaseHTTPServer пошлет этот запрос обработчику запросов. Наша реализация такого обработчика запросов, основанная на BaseHTTPRequestHandler, довольно скудна, так как ожидается, что всё, что он будет делать - запрашивать поля GET и HEAD в форме captcha?text=abcd. Следовательно, всё мы должны сделать - переписать методы do_GET() и do_HEAD() базового класса.
От запроса HEAD ожидается возвращение только заголовков запрошенного объекта, а не содержимого, чтобы сохранять время, за которое содержимое не изменится со времени последнего запроса (что-то, что может быть определено проверкой заголовка Last-Modified). Мы игнорируем такую аккуратность; мы возвращаем заголовки именно тогда, когда мы получаем запрос HEAD, но мы, тем не менее, будем генерировать полностью новое изображение. Это в некоторой степени расточительно, но зато код будет простым. Если важна производительность, можно разработать другую реализацию.
Наша реализация начинается с определения метода do_GET(), который просто вызывает метод do_HEAD(), который будет генерировать вопрос Captcha и возвращать заголовки клиенту. do_GET(), впоследствии, копирует содержание файлового объекта, возвращённого методом do_HEAD() в выходной файл, такой как объект обработчика запроса (выделено), который в свою очередь возвращает это содержимое клиенту (например, браузеру):
class CaptchaRequestHandler(
BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
f=self.do_HEAD()
shutil.copyfileobj(f,self.wfile)
f.close()
Метод do_HEAD() сначала определяет, получили ли мы правильный запрос (то есть, URI в форме captcha?text=abcd), вызывая метод gettext() (выделено, определяется позже в коде). Если URI некорректен, метод gettext(), возвращает None и тогда do_HEAD() возвращает клиенту ошибку File not found (Файл не найден), вызывая метод send_error() базового класса:
def do_HEAD(self):
text=self.gettext()
if text==None:
self.send_error(404, "File not found")
return None
Если был запрошен корректный URI, фактическое изображение генерируется методом captcha(), который возвращает имя файла сгенерированного изображения. Если этот метод терпит неудачу по любой причине, клиенту возвращается Internal server error (Внутренняя ошибка сервера):
try:
filename = self.captcha(text)
except:
self.send_error(500, "Internal server error")
return None
Если все прошло хорошо, мы открываем файл изображения, отсылаем клиенту ответ 200 (показывающий успешную операцию), и возвращаем заголовок Content-type, устанавливающий, что мы возвращаем png-изображение. Затем мы используем функцию fstat() с номером handle открытого файла в качестве аргумента, чтобы извлечь длину сгенерированного изображения и вернуть её как заголовок Content-Length (выделено), сопроводив временем модификации и пустой строкой, означающей конец заголовков перед возвратом открытого файлового объекта f:
f = open(filename,'rb')
self.send_response(200)
self.send_header("Content-type", 'image/png')
fs = os.fstat(f.fileno())
self.send_header("Content-Length", str(fs[6]))
self.send_header("Last-Modified",
self.date_time_string(fs.st_mtime))
self.end_headers()
return f
Метод gettext() проверяет, что запрос, передаваемый нашему обработчику запросов в переменной пути - правильный URI, сверяя его с регулярным выражением. Функция match() из модуля Питона re возвращает MatchObject (объект сопоставления), если регулярное выражение соответствует параметру, и None, если нет. Если есть соответствие, мы возвращаем содержание первой группы объекта сопоставления (символы, которые соответствуют выражению между круглыми скобками в регулярном выражении, в нашем случае значение текстового аргумента), в противном случае мы возвращаем None:
def gettext(self):
match = re.match(r'^.*/captcha?text=(.*)$',
self.path)
if match != None:
return match.group(1)
return None
Теперь мы добрались до задачи, специфичной для Блендера - сгенерировать рендеренный в 3D текст, который будет возвращён в виде png изображения. Метод captcha() принимает текст для рендера как аргумент, и возвращает имя файла сгенерированного изображения. Мы допускаем, что освещение и камера в .blend файле, в котором мы запускаем captcha.py, настроены правильно, чтобы удобочитаемо отображать наш текст. Следовательно, метод captcha() просто настраивает правильным образом объект Text3d и рендерит его.
Первая задача состоит в том, чтобы определить текущую сцену и проверить, присутствует ли объект с именем Text, который можно использовать заново (выделено). Заметьте, что вполне допустимо иметь другие объекты на сцене, чтобы ещё более затемнить отображение:
def captcha(self,text):
import Blender
scn = Blender.Scene.GetCurrent()
text_ob = None
for ob in scn.objects:
if ob.name == 'Text' :
text_ob = ob.getData()
break
Если не нашлось никакого ранее используемого объекта Text3d, создаём новый :
if text_ob == None:
text_ob = Blender.Text3d.New('Text')
ob=scn.objects.new(text_ob)
ob.setName('Text')
Следующий шаг - установить текст объекта Text3d в значение аргумента, переданного в метод captcha(), и сделать его трёхмерным, настроив глубину выдавливания. Мы также изменяем ширину символов и сокращаем расстояние между ними, чтобы ухудшить разделение. Добавление небольшого скоса (bevel) смягчит контуры символов, что может добавить трудностей для робота, различающего символы, если настроено искусное освещение (выделено). Мы могли бы решить использовать другой шрифт для нашего текста, который ещё труднее для чтения ботом, и здесь как раз место для установки такого шрифта (смотри следующий информационный блок).
Чего-то не хватает
Документация API Блендера имеет небольшой пропуск: как будто не существует способа настроить другой шрифт для объекта Text3d. Тем не менее, есть недокументированный метод setFont(), который принимает объект Font в качестве аргумента. Код, выполняющий изменение шрифта должен выглядеть похожим на это: