• Data:URL средствами браузера

    Думаю, зачем нужен data:url объяснять не стоит. Несмотря на проблемы с применением в IE, data:url незаменим, когда нужно отдавать HTML-страницу в виде одного файла (очень удобно такие файлы кэшировать в приложениях). Мне в последнее время приходится с ним довольно много работать и я был озадачен поиском хорошего инструмента, который смог бы легко кодировать графические файлы в base64. Критерии к инструменту следующие:

    • drag’n’drop;
    • возможность конвертации сразу нескольких файлов;
    • удобное копирование конечного результата;
    • должен работать на Маке;
    • няшный интерфейс с прЕкольными анимашками )))))))

    Беглый поиск в интернете удовлетворительных результатов не дал. Есть утилитка от Sveinbjorn Thordarson, которой я пользовался раньше, но она очень неудобная: принимает только по одному файлу, а результат нужно вычленять из <img>-тэга (там есть ссылка на маковский дроплет, который у меня не завёлся). Duris смущает тем, что требует готовую страницу, доступную где-то в интернете (слишком сложно для преобразования 2—3 файлов).

    Поэтому я решил создать свой веб-сервис, который будет удовлетворять этим требованиям. Когда я только принялся его писать, возникло здоровое чувство жлобства: зачем мне создавать онлайн-сервис, которым бесплатно будут пользоваться десятки, а то и сотни человек ежедневно, да ещё и за трафик платить из своего кармана? Может, современные браузеры уже могут делать такие штуки без помощи сервера?

    Как оказалось, вполне себе могут. Вот что у меня получилось. Работает, правда, не везде: только Firefox 3.6, Safari 4, последний Google Chrome (только Windows-версия). Для Safari и Chrome нужно сначала скачать себе эту страничку и запустить её локально (почему так узнаете, дочитав статью). Несмотря на такие ограничения, поддержки этих браузеров вполне достаточно для современного веб-разработчика.

    Дальше будет много текста про то, как создавался этот сервис.

    Начало

    Помимо выполнения сугубо утилитарных функций (кодирование бинарного изображения в base64 налету), этот сервис в первую очередь был плацдармом для обкатки новых браузерных технологий, о которых все говорят, но толком не используют. В частности, это CSS Transforms, CSS Transitions и CSS Animations. Поэтому работа была более исследовательской, нежели практической. В качестве инструментария я выбрал jQuery для рутинных DOM-операций и свой jTweener для анимаций (его очень легко адаптировать под любые CSS-свойства). Итак, начнём.

    Firefox

    В новом Firefox 3.6 появилось много нововведений, одно из которых — поддержка drag’n’drop. Причём таскать и бросать можно не только локальные блоки на веб-странице, но и внешние файлы. Перетаскиваемые файлы можно «поймать» с помощью JS и что-нибудь с ними сделать, не перезагружая страницу. Для этих целей существуют специальные объекты вроде Clipboard и FileReader, позволяюще получить и тут же прочитать файлы.

    Вообще, в Firefox 3.6 задача кодирования перетаскиваемых файлов в base64 решается элементарно: вешаем на окно обработчик события drop, в котором из объекта события достаём список перетаскиваемых файлов и читаем их с помощью FileReader. Примерный код решения:

    function handleFiles(evt) {
    	// запрещаем бразеру открывать перетаскиваемые файлы
    	evt.stopPropagation();
    	evt.preventDefault();
    
    	// список перетаскиваемых файлов
    	var files = evt.dataTransfer.files;
    
    	// читаем файлы
    	for(var i = 0; i < files.length; i++) {
    		var reader = new FileReader();
    		reader.onloadend = function(e) {
    			// в e.target.result содержится изображение в формате data:url
    			console.log(e.target.result);
    		};
    		reader.readAsDataURL(files[i]);
    	}
    }
    
    document.addEventListener('drop', handleFiles, false);
    

    Обратите внимание вот на что: если используете jQuery, то привязать событие drop через $(document).bind('drop', handleFiles); не получится, привязывать нужно именно через стандартный DOM-метод addEventListener(). Похоже, jQuery ещё не знает о таком событии.

    В принципе, на кодировании изображений только в Firefox 3.6 можно было и остановиться. Но моим главным инструментом является Safari, поэтому решил попытаться реализовать поддержку и это браузера.

    Safari (Webkit)

    Четвёртый Safari тоже поддерживает drag’n’drop, но получить содержимое файла в этом браузере оказалось сложнее (в то же время гораздо интереснее).

    Начнём с того, что Safari не поддерживает FileReader, то есть читать файлы просто нечем. В evt.dataTransfer.files (см. предыдущий пример) содержится список объектов класса File, у которого есть только 2 публичных свойства: fileName и fileSize. Мы можем получить только имя файла, но не полный путь к нему.

    Нужно найти способ, как получить полный путь к файлу, чтобы можно было хоть как-то загрузить его в браузер. Рассматриваем внимательно объект evt.dataTransfer, который является объектом класса Clipboard. У него есть метод getData(), позволяющий получить содержимое буффера обмена. Но этому методу нужно передать строку с названием типа данных, в котором хотим получить данные. Доступные типы определены в свойстве types. Простым перебором выясняем, что если передать тип text/uri-list, то получим список абсолютных путей ко всем файлам, разделённый переводами строк:

    function handleFiles(evt) {
    	// список перетаскиваемых файлов
    	var files = evt.dataTransfer.getData('text/uri-list');
    
    	console.log(files);
    	// выведет:
    	// file:///path/to/image1.png
    	// file:///path/to/image2.jpg
    }
    

    Итак, полдела сделано: мы получили список абсолютных путей к файлам, которые можем загрузить в браузер. Первая мысль, которая у меня возникла: создать <img> тэг, указав в качестве src путь к файлу, а после загрузки отрисовать его в canvas и получить data:url через метод toDataURL(). Однако эту мысль сразу же отбросил: во-первых, мы получим совершенно новое изображение, а не то, которое отдавали. Во-вторых, не понятно, что делать в JPEG-изображениями. В toDataURL() можно отдать тип, в котором хотим получить файл, но это будет то же самое, что сохранить JPEG как PNG, а потом обратно сохранить в JPEG, но уже с неизвестными параметрами сжатия.

    Второй способ, который пришёл мне в голову, это воспользоваться старым добрым XMLHttpRequest для загрузки файла. В принципе, идея неплохая, но есть одно жирное «но»: данные в responseText будут автоматически перекодированы браузером в текущую кодировку, что, естественно, нарушит целостность данных. В свежих версиях XMLHttpRequest (например, в IE8) есть свойство responseStream, в котором содержатся «чистые» байты файла, но Safari его не поддерживает.

    Выходом оказался хак, найденный где-то на MDC. Суть его заключается в том, что если у объекта класса XMLHttpRequest переопределить тип и кодировку файла с помощью метода overrideMimeType(), то в responseText окажутся правильные данные. В последних версиях jQuery у метода jQuery.ajax() в качестве параметра можно отдать метод xhr(), который должен вернуть XMLHttpRequest, с помощью которого будут загружаться данные. Вот как можно загрузить «чистые» данные:

    $.ajax({
    	url: file_path,
    	xhr: function(x) {
    		var xhr = new XMLHttpRequest();
    		xhr.overrideMimeType('text/plain; charset=x-user-defined');
    		return xhr;
    	},
    	success: function(data) {
    		console.log(base64_encode(data));
    	}
    });
    

    В метод success пришло правильное содержание файла, которое теперь нужно просто закодировать в base64 (соответствующая JS-реализация была найдена на просторах интернета).

    Копирование в буфер

    Файлы мы загрузили, перекодировали и вывели, теперь нужно придумать, как их удобно скопировать в буфер. Выводить здровенное <textarea>-поле и заставлять пользователя каждый раз выделять и копировать эти данные как-то совсем некошерно. Нужно сделать кнопочку, по нажатию на которую в буфер обена будут попадать нужные данные. В этом случае не нужно будет перегружать интерфейс ненужным данными, а также можно будет вывести несколько кнопок, которые будут копировать данные в разных форматах: обычный data:url, картинка и background-image.

    Единственный известный мне способ программно запихнуть данные в буфер обмена, это использование небольшой флэшки (флэшукапец, ага). Подробно об этом написано в блоге CSSing.org.ua, я же использовал слегка допиленную версию ZeroClipboard.

    Проблемы использования флэша на сайте уже много раз обсуждались, я же напишу о тех, которые возникли в разрабатываемом сервисе. Не знаю, как на винде, но на Маке одно только присутствие флэша на странице уже нагружает процессор, даже если эта флэшка ничего не делает. Причём, чем больше флэшек, тем больше нагрузка. Уже на 3-х загруженных файлах (у каждого 3 кнопки копирования; итого 3×3=9 флэшек) мой Core 2 Duo был загружен на 25%, при том что ни одного пикселя на странице не шевелилось. Ещё один побочный эффект — это влияние на анимацию. Когда пользователь удаляет блок с картинкой, содержимое блока тут же пропадало.

    Поэтому я сделал так: флэшки добавляются только тогда, когда пользователь наводит курсор на блок файла, и исчезают, когда уводит. Обе проблемы были решены, но владельцам Firefox достался немного неприятный побочный эффект в виде моргающих надписей на кнопках, когда флэшки исчезают (надеюсь, меня простят за это).

    Только я хотел нажать на кнопку «Опубликовать статью», как внутренне чувство заставило проверить всё ещё раз. Инстинкт меня не подвёл. На Маке я использую флэш-плагин версии 10,0,42,34, а на винде поставил самый свежий — версии 10.0.45.2. Несмотря на небольшую разницу в версиях в самой свежей сборке не работает копирование в буфер при локальном просмотре страницы. То есть пользователи Chrome, скачавшие страничку к себе на компьютер, попросту не смогли бы ничего скопировать. Похоже, Adobe решил окончательно закрутить гайки с буфером обмена.

    После часа безуспешного гугления был придуман хак, который позволяет копировать данные без использования флэша. Суть его заключается в том, что нужно создать на странице блок со свойством contentEditable="true", записать туда необходимую строчку через innerHTML, навести фокус (в этот момент браузер автоматически выделяет содержимое блока) и вызвать document.execCommand('copy'):

    <div id="copy-clip" contenteditable="true"></div>
    <script type="text/javascript">
    	function doCopy() {
    		var obj = document.getElementById('copy-clip');
    		obj.innerHTML = 'my new data';
    		obj.focus();
    		document.execCommand('copy')
    	}
    </script>
    

    По крайней мере при локальном запуске это работает, причём так, как надо.

    Анимация

    А теперь самое вкусное. Я давно присматривался к CSS трансформациям и анимациям, хотелось попробовать их на реальных проектах (подчёркиваю, речь идёт о качественной реализации реальных задач, а не о дурацких демках из разряда «смотрите, оно крутится!»). На данный момент CSS-трансформации поддерживают Safari (Webkit) и Firefox 3.6, CSS Transitions and Animations — только Webkit. Про Opera 10.5 молчу, ибо пользоваться этим абсолютно невозможно из-за чудовищных тормозов.

    Что я могу сказать про CSS-анимации в Safari: реализованы они довольно плохо. Есть довольно много неочевидных проблем. Для своего сервиса мне удалось их кое-как исправить, но не знаю, насколько эти проблемы могут быть решены в более крупных проектах.

    Вот что мне удалось узнать после работы с модными CSS-свойствами:

    1. Свойства вроде -moz-box-shadow очень сильно влияют на производительность. Уже на 7-ом блоке с файлом, у которого указано это свойство, начали появляться тормоза. Чем больше блоков — тем больше тормозит. Пользуйтесь CSS-декорациями вмеру.
    2. Одна из главных проблем при использовании CSS Transitions — это не совсем очевидный способ указания блоку начальных координат. Например, вы указали, что у блока должны плавно изменяться свойства left и top: -webkit-transition-property: left, top. Для того, чтобы переда началом анимации переместить блок в некие начальные координаты, плавные переходы нужно отключить. Сделать это можно обнулив либо -webkit-transition-property, либо -webkit-transition-duration:
      $(elem).css({
      	'-webkit-transition-duration': '0',
      	top: 10,
      	left: 20
      });
      

      А вот для того, чтобы включить плавный переход, нужно сначала вернуть отключённое transition-свойство, а уже потом, через setTimeout выставить нужные координаты:

      $(elem).css({
      	'-webkit-transition-duration': '0.5s'
      });
      
      setTimeout(function(){
      	$(elem).css({
      		top: 100,
      		left: 200
      	});
      }, 1);
      	
    3. В Webkit-браузерах для анимации перемещения объектов лучше использовать связку CSS Transition/Animation и translate(x, y) из CSS Transforms. Трансформации получают аппаратное ускорение (по крайней мере на Маке), а анимации включают субпиксельное сглаживание, что даёт полее плавное и естественное движение:
      subpixel

      Простое указание дробных пикселей (например, так: -webkit-transform: translate(5.5px, 1.6px);), к сожалению, подобного эффекта не дают.

    4. В следствие аппаратного ускорения CSS-преобразований, советую следить за размером блока. Если анимируете блок, ширина или высота которого больше 2000 пикселей (для айфона — 1024 пикселя), перед началом анимации блок «моргнёт». Судя по всему, это как-то связано с размером текстуры в OpenGL.
    5. После того, как такая анимация отработала, блок с файлом начало в прямом смысле слова «колбасить»:
      при наведении курсора на блок (после того, как отработала анимация появления) кнопки копирования соседних блоков начали прыгать куда-то вверх, а у надписей «поломалось» сглаживание:

      bug1

      Помогло, как ни странно, указание контейнеру с блоками position: relative;, а текстовым надписям — background: #fff; (здравствуй, старина IE).

    6. При наведении курсора на картинку она увеличивается/уменьшается с помощью CSS Animations (в Firefox — JS-анимация масштаба). Работает вроде неплохо, за исключением иногда «моргающей» тени и другого типа сглаживания у картинки. Но когда я указал z-index контейнеру с файлами, увидел вот такую картину:
      bug2

      Блоки произвольно исчезали и появлялись во время анимации. Помогло удаление z-index у контейнера. В моём случае это не критично, но подозреваю, в более крупных проектах с этим будут проблемы.

    Заключение

    Ещё года 2—3 назад задачи вроде перекодирования файлов прямо в окне браузера считались невыполнимыми. Но уже сегодня можно смело говорить, что браузеры могут не только страницы показывать, но и выполнять вполе утилитарные задачи. Теперь необязательно изучать фреймворки вроде Qt, чтобы написать кросс-платформенное GUI-приложение. Вполне достаточно накопленных в веб-разработке знаний, а современные JavaScript-движки способны быстро переваривать довольно большие объемы данных. Кто знает, может, скоро начнётся эра повального портирования существующих десктопных инструментов на JavaScript 🙂 Лично я получил огромное удовольствие не только от результата, но и от процесса создания этого небольшого сервиса.

    UPD: Иван Михайлов сделал Cocoa-оболочку для этого сервиса, теперь его можно запускать как обычное Мак-приложение.

  • 69 комментариев

    1. zema
      24 февраля 2010

      Сергей, ты хоть когда-нибудь спишь? O_o

    2. Ptico
      24 февраля 2010

      Мегаманьячество! Особенно с клипбордом. Я так понимаю это только с вебкитом катит?

    3. Сергей Чикуенок
      24 февраля 2010

      Похоже, да. Более того, работать, скорее всего, будет только локально, так как почти все браузеры ставят жёсткое ограничение на эту функцию.

    4. 24 февраля 2010

      Крутота неимоверная.

    5. 24 февраля 2010

      ZeroClipboadr при работе с одной общего его же объявления, при копировании перебирает все предыдущие по DOMу элементы на которые он повешен, и дойдя до нужного копирует, потому для каждого объекта желательно создавать отдельное объявление, и после копирования можно смело его убивать 🙂

      вот такая вот простыня 😉

    6. Сергей Чикуенок
      24 февраля 2010

      В принципе, я так и делаю: флэшка пишется прямо в кнопку (из-за этого пришлось его допиливать), потом удаляется, когда отводишь курсор.

    7. 24 февраля 2010

      фидбек %)
      фф3.6 — в буфер не копирует, прынципово — но конвертирует 😉 (между клейкой и отклекой нужно наверное таймаут)
      хром 5.0.322 — вообще ничего не происходит
      сафари 4.* (не запускал с прошлого года) — тоже ничего
      зы: винда 7

    8. 24 февраля 2010

      вот http://deer.org.ua/samples/encodings.html тоже с ЗК боролся, с подобной проблемой, не помню как решил %)

    9. homm
      24 февраля 2010

      > записать туда необходимую строчку через innerHTML
      Что-то мне кажется, что через innerText будет безопаснее.

    10. 24 февраля 2010

      http://c.pages.org.ua/base/
      ФФ заработал, глюки какие-то о_О… и только с первой кнопкой, если остальные поклацать, то 1я раза с третьего даст желанный результат 🙂

      У тебя при каждом хувере, любой кнопке из трёх, ЗК создаёт 3 клиента 🙂 и не убивает… потёки памяти будут огого 😉 В моём примере, ЗК создаёт столько клиентов сколько ячеек %) не больше не меньше %)

    11. 24 февраля 2010

      ФФ 3.6, перетягиваю картинку никакой реакции.

      Что-то не так делаю?

    12. Бардадым Денис
      24 февраля 2010

      Интересно, только странно, что говоря про кроссплатформенность, вы вспомнили Qt, а не java скажем.

    13. gfranco
      24 февраля 2010

      Ну чёрт его знает…
      sudo port install base64
      base64 someImage.png | pbcopy

    14. 24 февраля 2010

      Мне вот интересно стало… Если браузер может считывать локальные файлы с компьютера пользователя через JS не является-ли это дырой в безопасности?
      Не так глубоко вник в проблему, но ведь при желании так можно файл с конфиденциальными данными стянуть..

    15. rinaatt
      24 февраля 2010

      Извините за оффтопик… Когда мне надо было сконвертить картинку в base64, я использовал Notepad++. Вполне удобно для 1 или 2 файлов.

    16. 24 февраля 2010

      Браво! Жаль, что не ведёшь английский блог, ajaxian.com бы заинтересовался.
      Кстати, в четвертом виндовом Хроме при перетаскивании нескольких файлов загружается только один, плюс при удалении картинки остаётся однопиксельный артефакт в центре.

    17. rinaatt
      24 февраля 2010

      В Chrome 4 на Windows 7 не работает.

    18. romanov
      24 февраля 2010

      это всё, конечно, хорошо, но «data:url незаменим, когда нужно отдавать HTML-страницу в виде одного файла (очень удобно такие файлы кэшировать в приложениях)» для чего конкретно рассказать в двух пальцах можете?)

    19. я
      24 февраля 2010

      а фотошоп такой можешь написать? 🙂

    20. Сергей Чикуенок
      24 февраля 2010

      хром 5.0.322 — вообще ничего не происходит

      Я проверял в 4.0.249.89 (38071) на Win XP, всё работало. Попробую поставить семёрку в ближайшие дни, проверю, как там работает.

      ФФ 3.6, перетягиваю картинку никакой реакции.

      Какая ОС? Выдаёт ли какую-нибдуь ошибку в консоль? Какие расширения стоят в Firefox?

      Интересно, только странно, что говоря про кроссплатформенность, вы вспомнили Qt, а не java скажем.

      Qt — это фреймворк, которые позволяет создавать приложения на том же JavaScript. Java — это всё-таки целый язык программирования.

      Если браузер может считывать локальные файлы с компьютера пользователя через JS не является-ли это дырой в безопасности?

      Браузер может прочитать данные с того же домена, с которого загружена страница. Именно поэтому версию для Safari нужно скачать и запускать локально. Если же пытаться прочитать локальные данные с удалённого хоста, то браузер, конечно же, не позволит это сделать.

      Браво! Жаль, что не ведёшь английский блог, ajaxian.com бы заинтересовался.

      В принципе, я планировал специально для них написать мини-статью на английском, но надо сначала добиться, чтобы везде работало 🙂

      Кстати, в четвертом виндовом Хроме при перетаскивании нескольких файлов загружается только один

      Да, действительно. В dataTransfer.files содержится нужное количество файлов, а через dataTransfer.getData() приходит только один файл.

      это всё, конечно, хорошо, но “data:url незаменим, когда нужно отдавать HTML-страницу в виде одного файла (очень удобно такие файлы кэшировать в приложениях)” для чего конкретно рассказать в двух пальцах можете?)

      Например, у нас есть айфон-приложение, в котором вся справка хранится в виде набора HTML-файлов. Причём мы хотим поддерживать её в актуальном состоянии, то есть проверять, есть ли на сервере более свежая версия страницы. Если делать это как обычную HTML-страницу с внешними файлами и просто скармливать её встроенному вебкиту, то:

      1. Не факт, что страница вообще закэшируется, так как действуют ограничения на объем файла (если файл больше, по-моему, 27 КБ, то в кэш он не попадёт).
      2. Вебкит будет делать кучу запросов к серверу, чтобы проверить, не обновился ли внешний файлЮ расходуя драгоценных gprs-трафик.
      3. Мы не можем напрямую получить доступ к кэшу браузера, чтобы самим описать логику кэширования.

      Выход: самим долбиться на сервер и проверять, обновился ли файл. Если да — скачиваем, сохраняем в ПЗУ, и скармливаем вебкиту локальный файл. Но если у этого файла есть внешние ресурсы, то нам самим придётся писать специальный парсер, который будет доставать эти ссылки из файла и проверять, обновились ли они, опять же, тратя gprs-трафик. В случае с одним файом таких проблем нет.

      а фотошоп такой можешь написать?

      У меня были мысли самому написать свой идеальный графический редактор, заточенный под задачи веб-разработчика. То это займёт слишком много времени, да и у меня не хватает необходимых знаний.

    21. Мохов Олег
      24 февраля 2010

      В общем-то где заявлено, там и работает. Проверял в FF3.6 (Work), Chrome 5 (Fail), Safari 4 (Work) под маком. Только я правильно понял, что проблему с флешем до конца так и не удалось решить, FF начинал изрядно кушать процессор.

    22. romanov
      24 февраля 2010

      ubuntu x64, chromium 5 не даёт файлы бросать именно на вкладку с этим приложением. на другие бросается нормально..

    23. 24 февраля 2010

      Какая ОС? Выдаёт ли какую-нибдуь ошибку в консоль? Какие расширения стоят в Firefox?

      Win 7. Всё заработало после включения консоли.
      Плагины установлены: Firebug, adblock (отключил на сайте), html validator. Остальные не существенные.

    24. Сергей Чикуенок
      24 февраля 2010

      Всё заработало после включения консоли.

      Мда, в который раз забываю убрать трассировку с production-скриптов 🙂 Сейчас всё должно нормально работать

    25. derek
      25 февраля 2010

      Приложение очень крутое!

      Уже активно его использую. Правда, именно поэтому, хочется больше нативности. Хочется, например, драг-н-дропнуть файлы на иконку, или спрятать апп пока не понадобится (в браузере с табами много возни)

      Вообщем, написал маленькую обертку на Cocoa

      enjoy:
      http://tinyurl.com/ykd2rjr

    26. Сергей Чикуенок
      25 февраля 2010

      Круто, а вы можете отлавливать файлы, которые бросаются на иконку в доке и вызвать специальную JS-функцию на странице? Можно было бы добавить и бросание в док

    27. derek
      25 февраля 2010

      Так это уже сделано )

    28. Сергей Чикуенок
      25 февраля 2010

      Отлично. Я немного отрефакторил код, теперь есть метод bdu.externalDrop(file) (вместо dndCocoa()), куда можно отдать путь к файлу (либо список путей, резделённых переводами строк), а также специально для приложения делается шрифт крупнее.

      Можете обновить скрипт? И ещё, можете открывать окно размером 765 пикселей? Тогда поместится 3 блока в ряд. И вот эту иконку поставить, поки никто не нарисовал лучше 🙂

    29. Владимир Колесников
      25 февраля 2010

      В ФФ3.6 можно делать без FileReader, синхронно через e.dataTransfer.files[0].getAsDataURL('image/png') code.

      Я сам вебапом режу бэкгрануды на 9 частей для ukijs.org.
      Скринкаст про это (english).

    30. Сергей Чикуенок
      25 февраля 2010

      Атрибут для getDataAsURL() вроде как не нужен: https://developer.mozilla.org/en/DOM/File#getAsDataURL.28.29

      Но спасибо за наводку, буду знать

    31. Олег Подчашинский
      25 февраля 2010

      Для Фаерфокса 3.5.6 теперь тоже надо локально запускать? Еще вчера не надо было.

    32. Сергей Чикуенок
      25 февраля 2010

      В Firefox 3.5 вообще не работает

    33. Олег Подчашинский
      25 февраля 2010

      Хм, вчера работало, даже с анимацией.

    34. Сергей Чикуенок
      25 февраля 2010

      UPD: в Chrome теперь сразу показываются все брошенные файлы (раньше показывал только один), добавлена теоретическая поддержка Firefox 3.5 (локально, как с Safari; и то, если с версией флэша повезло).

    35. kizu
      25 февраля 2010

      Кстати, а насколько сложно было бы сделать подобный бандл для текстмейта?
      Чтобы можно было как в зенкодинговом экшне с апдейтом картинок — навестись на адрес картинки в src или url и заменять адрес картинки на data:url?

      Ну и как бонус можно было бы ещё экшн сделать, который бы во всплывающем окне показывал что за картинка там закодирована, было бы удобно.

    36. Сергей Чикуенок
      25 февраля 2010

      Ммм, хорошая идея. Сделать можно, заведи, пожалуйста, тикет в проекте.

    37. kizu
      25 февраля 2010
    38. 27 февраля 2010

      Спасибо! Уже в закладках. Хоть в Хроме пятом у меня тоже не работает, зато в FF все превосходно.

    39. Сергей Чикуенок
      28 февраля 2010

      В четвёртом хроме должен работать (локально)

    40. Ruslan
      5 марта 2010

      Prikol’no! (zaranee sorry za translit).
      Po povodu animations v Safari ya toje s nimi igralsa okolo polutora let nazad. To chto vishlo mojno posmotret’ tut:
      http://bdn.backbase.com/blog/rus/advanced-3d-animations-and-transitions

    41. 24 марта 2010

      Сергей, если я правильно все понял, то с помощью этого можно сделать аналогичный загрузчик, как на сайте вконтакте. Т.е. не только предпросмотр изображений, но возможно и изменение качества и ресайзинг (все это на js, без flash)?

    42. Сергей Чикуенок
      24 марта 2010

      Технически — да, но это будет не везде работать (только в указанных браузерах) + нужно проделать огромную работу по конвертации JPEG-кодировщика на JS

    43. 24 марта 2010

      Т.е. это пока в перспективе может быть. Сейчас браузеры к этому не готовы и рациональнее использовать флэш для конкретно этой цели?

    44. Сергей Чикуенок
      24 марта 2010

      Да, сейчас лучше использовать флэш

    45. B@rmaley.e>
      5 апреля 2010

      > нужно проделать огромную работу по конвертации JPEG-кодировщика на JS
      И не только JPEG. Нужны еще декодировщики для остальных форматов.

    46. Kaktus
      12 апреля 2010

      FAIL.
      В последней версии Chrome не работает, в Firefox промаргивает, но не копируется, сафари не юзал.

    47. B@rmaley.exe
      16 апреля 2010

      После недавнего обновления GMail’а, там можно стало загружать файлы drag-and-drop’ом. Работает эта штука на чистом JS, а значит способ читать файлы должен быть.

    48. Сергей Чикуенок
      16 апреля 2010

      Прочитать произвольный файл прямо в браузере и получить ссылку на файл для отправки на сервер — абсолютно разные вещи.

    49. Сергей Чикуенок
      16 апреля 2010

      Кстати, в Gmail используется FileReader API — такой же, как и в Firefox 3.6. Этот API доступен только в Chrome и Firefox 3.6, в Safari и более старых сборках Webkit не доступен

    50. B@rmaley.exe
      16 апреля 2010

      Chrome 5.0.342.5:
      typeof FileReader -> undefined

      P.S. Каким образом, зная ссылку на файл, отправить его на сервер?

    51. Сергей Чикуенок
      18 апреля 2010

      Значит, Ajaxian ввёл меня в заблуждение 🙂 Тогда отправку файлов аяксом я бы сделал так: из dataTransfer получаем список объектов класса File (описано в этой статье) — это и есть ссылки на файлы. В новых спеках XMLHttpRequest есть возможность указать в методе send() ссылку на файл, тем самым инициировать его загрузку на сервер.

    52. B@rmaley.exe
      19 апреля 2010

      В XHR2 есть возможность передавать аргументом методу send объект класса FormData, который, в свою очередь, заполняется методом append путем передачи 2 аргументов: имени параметра и значения. Вот значение как-раз может быть экземпляром класса File.
      Но вот проблема:
      typeof FormData -> undefined

      Как сделал гугл у себя — непонятно…

    53. Сергей Чикуенок
      19 апреля 2010

      Гугл получает объекты File из dataTransfer (который создается в drag’n’drop), а не из FormData

    54. B@rmaley.exe
      19 апреля 2010

      Откуда получать объекты я знаю. Меня интересует, как их отправлять.

    55. Сергей Чикуенок
      19 апреля 2010
      var xhr = new XMLHttpRequest();
      xhr.send(evt.dataTransfer.files[0]);
      
    56. B@rmaley.exe
      19 апреля 2010

      И как его принимать на сервере?

    57. B@rmaley.exe
      21 апреля 2010

      Сам же и отвечу на свой вопрос: php://input (В других языках искать свой входной поток).

    58. blia
      8 декабря 2010

      Что-то не так. Сосоа-программка не копирует код в буфер.

    59. Сергей Чикуенок
      8 декабря 2010

      В Safari 5 прикрыли эту «дырку» с копированием в буффер, описанную в статье.
      Лучше использовать Zen Coding для преобразования в Data:URI

    60. blia
      8 декабря 2010

      Ясно. Да в ff завелось.
      А можно про кодирование в Zen Coding подробнее?

      Сам пользуюсь Zen Css и Zen Html для textmate

    61. Сергей Чикуенок
      8 декабря 2010

      Zen CSS/HTML — это статичные сниппеты. Нужно поставить полноценный Zen Coding из Developer preview: https://github.com/sergeche/zen-coding/downloads

    62. blia
      8 декабря 2010

      Отлично. Спасибо, Сергей.

    63. anton
      20 июля 2011

      Добрый день, Сергей.
      А этот товарищ у вас спросил разрешения? Или просто так своровал исходники? http://azbukaweb.ru/data-url/

    64. Сергей Чикуенок
      20 июля 2011

      anton, автор этого сайта просто взял мой код. Но я не против копирования своих статей/инструментов без моего ведома, если сохраняется мой копирайт: http://azbukaweb.ru/base64coder-img

    65. marksman
      29 августа 2011

      при использовании связки transition и transform появляется мерцание элемента перед анимацией в webkit мобильных-браузерах (iphone,android, в blackberry ваще пропадает изображение), приэтом размеры блока намного меньше чем 1024px, и никак не получилось побороть.

    66. Антон Симонов
      20 декабря 2011

      Сергей, для Виндоус есть такая утилита, Blijbol Data URI Generator, http://software.blijbol.nl/en/pc/datauri — наверняка можно сделать аналог и для мака. Помещается в контекстном меню Send to…, копирует результат в буфер.

    67. Сергей Чикуенок
      20 декабря 2011

      Антон, я уже давно пользуюсь встроенным конвертером в Zen Coding

    68. alexander
      7 мая 2012

      напишите пожалуйста как кодировать через zen coding(phpstorm), не нашел информацию

    69. 13 ноября 2012

      В последнем фоксе и хроме уже не работает, даже ошибки нет, наверное днд запретили