Data url не работает

Евгений Степанищев

Пару лет назад я занимался проблемой data URL в Internet Explorer, добился определённых результатов, но то, что получилось, использовать было невозможно. Data URL (иногда его ещё называют «протокол data:») — возможность вставлять ресурсы (графику, CSS, JavaScript и так далее) в HTML код.

Выглядит это примерно так:

В Data URL указывает тип содержимого и способ его кодирования. Способа кодирования два — base64 (именно он и указан в примере), увеличивающий содержимое на треть и URL encoding (в этом случае способ кодирования не указывается) — привычный многим способ кодирования при помощи %xx, в лучшем случае вообще не увеличивает размер содержимого, в худшем — увеличивает в три раза.

Кстати, в настоящее время IE8b1 поддерживает data URL, но, увы, длиной не более 32Кб.

Вчера ночью мне пришла в голову идея как можно попытаться корректно совместить data URL и включение картинок через протокол mhtml. То, что у меня не получилось два года назад, получилось сейчас.

Результат — готовый код на PHP из двух функций. Первую функцию («bolk_data_uri_header») нужно вызвать в самом начале перед выводом любого вашего кода, вторую («bolk_data_uri») собственно для включения картинки в код. Надеюсь на примерах всё понятно:

Код самой библиотеки:

У данного метода, по сравнению с обычными data URL есть масса ограничений: необходим специальный заголовок в начале файла, т. е. этот метод невозможно использовать на чужих сайтах, этим методом нельзя воспользоваться (по крайней мере не в таком виде) для включения ресурсов внутрь CSS или JavaScript. В принципе, тут есть достаточно большое поле для экспериментов, возможно все или некоторые из проблем можно решить.

В разделе «храню» есть пример, который можно потестировать на имеющихся у вас браузерах. Уже протестировано на Opera 9.25 и 9.50b, FF 2.0.0.13 и 4 (Minefield), Safari 3.1 (Safari под iPhone — тоже), Internet Explorer 6.0SP2 и 7.0, Sony PSP browser, Opera mini, Netscape Navigator 9.0.0.5.

Источник

data URI

Пару лет назад я занимался проблемой data URL в Internet Explorer, добился определённых результатов, но то, что получилось, использовать было невозможно. Data URL (иногда его ещё называют «протокол data:») — возможность вставлять ресурсы (графику, CSS, JavaScript и так далее) в HTML код.

Подробнее о data URL можно узнать из свежей статьи на «Хабре» «Картинки в теле страницы с помощью data:URL». Хотелось только её дополнить двумя замечаниями: IE8b1 поддерживает data URL длиной не более 32Кб, в современных версиях других браузеров ограничений увидеть не удалось, Safari/Opera/FF показали изображения размером около 700Кб.

Вчера ночью мне пришла в голову идея как можно попытаться корректно совместить data URL и включение картинок через протокол mhtml. То, что у меня не получилось два года назад, получилось сейчас.

Результат — готовый код на PHP из двух функций. Первую функцию («bolk_data_uri_header») нужно вызвать в самом начале перед выводом любого вашего кода, вторую («bolk_data_uri») собственно для включения картинки в код.

Надеюсь на примерах всё понятно:

Код самой библиотеки:

Секрет в совмещении данных, чтобы IE, обратившись к странице по протоколу mhtml нашёл нужный кусор, «спрятанный» внутри тега, а остальные браузеры увидели бы картинку через data URL.

Код тестировался под Opera 9.50b, FF 2.0.0.13, Safari 3.1 и IE6. Предложения и результаты испытаний — прошу в комментарии.

Оригинал записи опубликован в моём блоге.

Источник

Встраиваем изображения — data:URL

Как ты, конечно, знаешь, браузер, встретив в HTML тег img, спешит отправить на сервер запрос для загрузки соответствующей картинки. Примерно так же обстоят дела и с CSS-свойством background-image. В общем, как только встречаем картинку — имеем дополнительный запрос (а это время и трафик, в том числе, потраченный на пересылку HTTP заголовка — около килобайта).

Вот такое вот поле для деятельности оптимизатору. Раз каждая картинка — это отдельный запрос, значит, чтобы уменьшить число запросов, нужно уменьшить число отдельных картинок. Поскольку просто выбросить картинки нам никто не даст, остается их объединять — склеивать разные изображения в один файл. Загружаются склеенные картинки одним запросом, а уже потом выбираются нужные участки (благо в CSS есть свойство background-position). Этот типичный подход описан в статье Спрайты: меньше картинок — больше скорость.

Схема data:URL

Но есть и другой вариант. А что, если картинки не клеить между собой, а внедрять прямо на место их использования — непосредственно в HTML и CSS файлы? Конечно, сами файлы при этом несколько «распухнут» — увеличатся в размерах, но зато все загрузится за один запрос. Выигрыш на заголовках может быть весьма ощутимым! И, как ты увидишь ниже, не только на заголовках.

Технически, такая «вклейка» возможна. Базируется она на схеме data:URL. Эта схема позволяет внедрить на веб-страницу данные так, как если бы они были подключены с помощью вызова внешних файлов. Оговорюсь, внедрение возможно не в произвольном месте, а именно в URL (например, в атрибуте src, тега img).

Читайте также:  Сбросила настройки ми бэнд 4 как настроить заново

Сразу предупрежу — метод не панацея. Имеет ряд существенных ограничений. Но, давай по порядку.

Как это выглядит?

Все очень просто. Имеем следующий синтаксис:

  • MIME-тип — тип встраиваемых данных (мы будем встраивать рисунки, поэтому, скорее всего, будет что-то типа image/gif или image/png );
  • base64 — означает, что данные закодированы в base64 (если параметр не указан, считается, что данные закодированы в ASCII);
  • данные — собственно набор байт — закодированное изображение.

На практике получатся примерно такие (или во много раз более длинные) громоздкие, но вполне валидные конструкции:

А что с кроссбраузерностью?

Закономерный вопрос. В настоящее время подавляющее большинство браузеров поддерживают эту технологию. Ни с Firefox, ни с Opera, ни с Safari, ни с IE8+ никаких проблем быть не должно.

Для IE6-7 существует альтернативное решение вставки изображений в виде mhtml-включений. Так что можно сказать, что все популярные браузеры позволяют использовать внедрение изображений.

Как обычно, не откладывая в долгий ящик, демо-пример странички с data:URL для фоновых картинок (CSS) и для тега img (HTML).

Как получить код?

С кроссбраузерностью разобрались, пример посмотрели. Теперь самое время, что бы кто-нибудь сказал: «Стоп! Что ты там за символы понавставлял в примере?! Где ты их взял? У меня же просто картинка! Файлик…».

Не беспокойся. За нас уже поработали. Существуют готовые сервисы, которым можно «скормить» файл-картинку и получить соответствующий ей код.

Про размеры картинок

Так как картинка вставляется в URL, на размер кода накладываются некоторые ограничения. Вообще говоря, по спецификации, браузеры обязаны поддерживать URL не менее 1Kb. На самом деле ситуация гораздо лучше. В ходе эксперимента выяснилось, что блок кода картинки до 32Kb можно смело использовать во всех популярных браузерах (FF, Opera, Chorme, Safari, IE6+).

При размере больше 32Kb пасует IE8. Но, если для IE8 использовать не data: URL, а MHTML-включение (как для IE6-7), то можно использовать код до 64Kb.

Важная оговорка! Цифры, приведенные выше, относятся именно к размеру base64-кода картинки. Фактический размер изначального изображения должен быть примерно на треть меньше. Таким образом, имеем безопасное ограничение для размера встраиваемой картинки примерно 20Kb.

В чем сила, брат?

Итак, можно с помощью специального сервиса превращать картинки в строки кода и вставлять их в HTML/CSS. Но это же уйма дополнительной работы! Для чего это все?

Преимуществ метода достаточно много. Вот перечень показавшихся наиболее существенными:

  • все внедренные данные попадают на страницу в результате одного запроса — даже на простенькой странице так можно выиграть десятки килобайт на заголовках HTTP, то есть уменьшить нагрузку на сеть и не терять время на ожидание обмена информацией между сервером и клиентом при каждом запросе;
  • некоторые браузеры имеют ограничение по количеству параллельных подключений к серверу, встроенные данные освобождают подключения для загрузки другого контента;
  • меньше используется файлов — значит меньше файлов попадет в кеш, в некоторых ситуациях это может быть важно;
  • дополнительная функциональность — например, браузер может перекодировать в data:URL картинку, находящуюся в буфере, и вставить ее в HTML поле ввода;
  • шаблоны e-mail сообщений могут содержать картинки, например, подпись или фоновый рисунок, без необходимости использовать вложения.

Обратная сторона медальки

Недостатков тоже хватает:

  • трудоемкость при разработке и поддержке. Мы не просто пишем адрес картинки, а еще и тратим время, кодируя/декодируя ее;
  • утверждается, что закодированные в Base64 данные примерно на треть больше по размеру, чем исходный файл изображения. Этот негативный момент можно устранить, если использовать gzip сжатие — такие данные будут хорошо жаться;
  • для HTML теряется выгода от кеширования — внедренные картинки, являясь единым целым с HTML-страницей, перезагружаются каждый раз, когда перезагружается документ;
  • браузеры имеют ограничения по длине URL, что определяет максимальный размер данных. То есть метод неприменим для больших картинок;
  • данные включаются как простой поток, и многие среды обработки не могут поддерживать контейнеры (вроде multipart/alternative или message/rfc822), чтобы обеспечить большую гибкость, типа метаданных, сжатия данных или согласования контента по языку.

Где применять?

Перечень достоинств и недостатков весьма внушительный. Однозначно одобрить или забраковать данную технологию невозможно. Просто она имеет ограниченную область применения.

Очевидно, что выигрыш от использования data:URL для CSS существенно больше, чем для HTML (где теряем выгоды от кеша и получаем дополнительный геммор с IE6-7). Так же имеем очень существенную оговорку о максимальном размере закодированного файла (да еще для разных браузеров он разный).

Вывод напрашивается сам собой: встроенные, при помощи data:URL, изображения имеет смысл использовать в CSS, для небольших фоновых картинок — получим выигрыш в быстродействии.

Подходит для высоконагрузочных проектов, или проектов, где важна скорость загрузки.

О производительности

update 23.02.11 by Ksayri Применение data:URL способно существенно снизить (до 10 раз) производительность некоторых браузеров. В частности это касается Firefox (который тратит очень много ресурсов на обработку base64) и IE6-7 (которым приходится иметь дело с mhtml). Чем больше будет data:URL на странице, тем больше будет тормозить.

Читайте также:  Как настроить язык phasmophobia

Поэтому сейчас оптимальным решением будет приметь сначала CSS спрайты, а затем преобразовывать минимальное количество спрайтов в data:URL.

Источник

Поддержка Data:URL Internet Explorer’ом

Многим известен данный способ отображения картинок, но особой популярностью он не пользуется, т.к. имеет проблемы с отображением в Internet Explorer (IE 6,7 — вообще не понимают, что им дают. А IE8 — принимает только картинки меньше 32кб).

Как же решить эту проблему?

Согласно RFC 2397, картинка (как и любые другие данные) должна быть представлена в следующем формате:
data:[ ][;base64],

Изучим синтаксис более подробно:

dataurl := «data:» [ mediatype ] [ «;base64» ] «,» data
mediatype := [ type «/» subtype ] *( «;» parameter )
data := *urlchar
parameter := attribute «=» value

Что же здесь такого интересного? Дело в том, что mediatype может содержать в себе дополнительные параметры (например, charset).
Соответственно, никто не запрещает нам хранить в нем свои данные.

К чему я все это?

Internet Explorer не может прочитать закодированные в base64 изображения, но спокойно может загрузить их, если мы укажем их url.
Так что, если указать url прямо в mediatype?

Сделать это можно примерно следующим образом:
data:image/png;src=habr.png;далее_base64_кодировка.

Это все, конечно, очень хорошо и интересно, но как же IE поймет, что дополнительный параметр и есть наша картинка?

Я предлагаю использовать behavior.
Это css-атрибут, поддерживаемый только в Internet Explorer и многим известный по такому проекту как PNGFix (одной из его реализаций).

Выглядеть это будет примерно так (код CSS):
#A <
background-image: url(data:image/png;src=habr.png;далее_base64_кодировка. );
behavior: url(ieb64.htc);
>

А это код ieb64.htc:

public:attach event =»ondocumentready» onevent =»ondocumentready()»/>
script type =»text/javascript» >
function ondocumentready() <
this .style.backgroundImage =
this .currentStyle
.backgroundImage
.replace(
/^url\s*\(\s*\ «?\s*data:[^;]+;src=([^;]+);.*$/,
function(all, url) <
return » url(\ «» + url + «\»)» ;
>
);
>
script >

Посмотреть демонстрацию можно здесь.
А тут можно скачать htc-файл.

Источник

К вопросу о кроссбраузерных Data URI

BASE64

Поскольку изображения передаются в base64, стоит осветить некоторые, связанные с этой кодировкой, моменты

  • Во первых: base64 понимает только [A-Za-z0-9+/].
    При дешифровке браузерами или ruby либой все прочее символы дропаются.
    Консольный base64 на линуксе их не дропает и выводит ошибку.
  • Во вторых: base64 конвертит каждые 3 исходных байта (в нашем случае, ASCII символы) в 4 ASCII символа.
    Поэтому декодированную CSS строку надо уравновешивать, к примеру, нулями, что бы она правильно себя вела внутри закодированного файла.

Формат секций в JPEG:[заголовок][data]

C jpeg все просто и описано у bolk‘а:

Открываем HEX-редактор:
FF D8 — заголовок JPEG для IE
FF E0 — объявление секции APP0, куда прячется всё до данных изображения,
«;background-color:url(data:image/jpeg;base64,» — это видят остальные браузеры.
Когда IE декодирует эту строку, то получается хлам, который ни на что не влияет
FF D8 — начало JPEG для остальных браузеров
«данные изображения» — это место видят уже все браузеры

Смысл в том, что бы строка в CSS выглядела как:

И дешифровалась в IE как:

А другие ее видели как:

Из-за особенностей base64 надо дополнительно передавать некоторое кол-во символов, что бы строка шифровалась\дешифровалась верно. Они вставляются до и после CSS. Количество просчитывалось и подбиралось опытным путем:
/9j/4AA0;background-image:url(data:image/jpeg;base64;00,

Мой скрипт, который это процесс автоматизирует:

#!/usr/bin/ruby
require ‘base64’
# тут строка ВСЕГДА равна одному значению:
a= «/9j/4AA0;background-image:url(data:image/jpeg;base64;00,»

#Основной файл
b=Base64.encode64( File .open( «#» , ‘r’ )<|f| f.read>)

# перегонка файла обратно в base64
#cat test | base64 | tr -d «\n» > jpeg64.txt
File .open( ‘temp2’ , ‘w’ )<|o| o.write(Base64.encode64( File .open( 'temp' , 'r' )<|f| f.read>))>
# File .delete( ‘temp’ )

c= File .open( ‘temp2’ , ‘r’ )<|f| f.read>.gsub(/\/9j\/4AA0backgroundimageurldataimage\/jpegbase6400/, «/9j/4AA0;background-image:url(data:image/jpeg;base64;00,» ).gsub(/\n/, «» )

File .open( ‘out_jpeg64’ , ‘w’ )<|s| s.write( "#\);» )>
File .delete( ‘temp2’ )
# можно вставлять в css
# cat output64 | tr -d «\n»
# и хорошо поверить mhtml.

* This source code was highlighted with Source Code Highlighter .

70

  • Переместить содержимое General Color Table в Local Color Table
  • Я выбрал второй вариант, это делает base64 строку более читаемой и позволяет конвертировать любые не анимированные gif.

    Более менее стандартный вариант секций GIF: [заголовок][размер][data][00]

    Многие GIF имеют не совсем корректный порядок полей. Например если сделать `convert jpeg gif` то полученный файл адекватно обрабатываться скриптом не будет. Юзайте GIMP.

    Первые 13 байт это та инфа, сокращать которую нельзя. Причем 11 байт является сложно-составным и описывает Global Color Table. Его меняем на 00
    Вырезаем таблицу цветов (от 14 байта и до камента — 21 FE xx, где xx — размер коммента)
    Коммент с css и первыми 13ю байтами.
    Вырезаем таблицу цветов (от 14 байта и до камента — 21 FE xx, где xx — размер коммента)
    ‘Внутренний кoммент’ длиной в 1 символ
    Вырезаем таблицу цветов (от 14 байта и до камента — 21 FE xx, где xx — размер коммента)
    2c 00 00 00 00 — Image descriptor. Его 10й байт является сложно-составным и описывает Local Color Table. Переносим из 11-го байта все что переносится (объявить Local Color Table, сортирована\нет, размер Local color table), подробнее в спецификации формата.
    Вставляем таблицу цветов
    Продолжение Image descriptor

    Смысл в том, что бы строка в CSS выглядела как:

    Читайте также:  Электрический полотенцесушитель сломалась кнопка включения

    При том что до всех правок файл выглядел как:

    Мой скрипт для автоматизации процесса:

    #!/usr/bin/ruby
    # CONVERT INCORRECTLY TRANSFER DATA. USE GIMP INSTEAD
    # USE: ./GIF_SCRIPT.RB [GIF_FILE]
    require ‘base64’

    # FUTURE HEADER
    header=orig[0..25]

    # GREP GENERAL COLOR TABLE
    # [26..1565]/6 = 256 BYTE (MAX SIZE OF COLOR TABLE)
    color_table=orig[26..1565][/(.*)21fe/,1]
    if color_table. class == NilClass
    color_table=orig[26..1575][/(.*?)2c0000/,1]
    end

    # FOR DEBUGING
    #puts color_table
    #puts color_table.length
    puts «COLORS IN PALLETE: #«

    # GIF IMAGE DATA
    data=orig[/2c0000.*/]

    # SAVE 11 BYTE ‘S INFO AND ADOPT IT FOR LOCAL COLOR TABLE
    eleven=header[20..21].to_i(16).to_s(2)
    local_mix=»10#00#«.to_i(2).to_s(16)

    # 11 BYTE TO ZERO
    header[20..21]=»00″
    # DECLARE LOCAL COLOR TABLE
    data[18..19]=local_mix

    # MAGIC COMMENT
    comment=Base64.decode64(«;background-image:url(data:image/gif;base64;pzd,»).unpack(«H*»).to_s

    # WRITE ALL IN ONE FILE
    var=header+»21fe313030″+comment+header+»21fe013000″+data[0..19]+color_table+data[20..-1]
    File.open(‘ out .gif ‘,’ w ‘)

    # MAKE STRING CSS READEABLE
    c=File.open(‘ temp ‘,’ r ‘)<|f| f.read>.gsub(/backgroundimageurldataimage\/gifbase64pzd/,»;background-image:url(data:image/gif;base64;pzd,»).gsub(/\n/,»»)
    File.delete(‘ temp ‘)

    # JUST PASTE TEXT FROM THIS FILE TO CSS
    File.open(‘ out_gif64 ‘,’ w’)<|s| s.write( "#\);» )>

    * This source code was highlighted with Source Code Highlighter .

    Для анимированного гифа скрипта нет. Я считаю что лучше использовать анимированными CSS sprites.

    Теоретические выкладки:

    • Для каждого кадра делать Local Color Table смысла не имеет, т.к. это увеличит размер.
    • Анимированные гифы с кол-вом цветов 64 могут обрабатываться с включением General Color Table в коммент
    • Application Extension и Comment Extension могут идти подряд, что увеличивает возможный размер x2.
    • На просторах интернета я встретил информацию о том, что в Application Extension фактически 2 блока задают размер.

    21 ff SizeSize ‘NETSCAPE2.0’ SizeSize 01 00 00, где SizeSize — 2 байта отвечающие за размер, а 01 байт отвечающий за infinitive loop.

  • Что, в теории, может предоставить возможность ‘забить’ большее кол-во цветов. Но все-равно меньше 256 (около 230).
  • После gif это тихая гавань. У секций размер не ограничен, у них 4байтные заголовки и их очень удобно искать. Для сравнения, для gif я ломал голову и дебажил скрипт почти весь день, а для png все сделал за час.

    Формат секций в PNG: [размер(4 байта)][data][CRC(4 байта)]

    И тут не обошлось без подводных камней. CRC очень важен для IE, если CRC битый то IE не будет отображать картинку. Всем же остальным глубоко параллельно битый он или нет.

    Многие PNG имеют не совсем верную структуру, во всяком случае, мой скрипт с нми работать не будет, пока не прогнать их через optipng. Помимо оптимизации изображения, эта прога выставит поля в нужном порядке. Также, мною замечено что Photoshop иногда режет поля sRGB и им сохраненные png обрабатываются не всегда.

    CSS будем прятать в секции tEXt

    PNG надо сразу заоптимизировать с помощью optipng, потом нарезать таким образом, что бы tExt был сразу за IHDR.
    В секции tEXt обязательно должен передаваться keyword00, его длина учитывается в общей длине секции. У меня это ‘Comment ‘

    Общий порядок:

    IHDR
    tExt
    Другая служебная информация
    data

    Было:

    Стало:

    Скрипт хорошо комментирован, и в спецификации тоже можно многое почерпнуть

    IE6 не видит прозрачности, иногда это можно исправить с помощью bKGD выставляя нужный Background color.

    После чего запускаем `optipng -fix FILE` что бы исправить CRC секции tEXt

    Мой скрипт для автоматизации процесса:

    #!/usr/bin/ruby
    #
    #. RUN optipng FIRST .
    #
    # USE: ./PNG_SCRIPT.RB [PNG_FILE]
    require ‘base64’
    # OPEN GIF FILE IN HEX
    orig= File .open( «#» , ‘r’ )<|f| f.read.unpack( "H*" )>.to_s

    #sRGB — 73 52 47 42 & -4b (8 characters)
    #srgb_phys=orig[66..171]
    #check for tEXt existence
    if orig[/74455874/]. class == NilClass
    srgb_phys=orig[/(.<8>73524742.*?)49444154/,1][0..-9]
    else
    srgb_phys=orig[/(.<8>73524742.*?)74455874/,1][0..-9]
    end

    #tEXt — 74 45 58 74 –њ–Њ—Б–ї–µ–і–љ–Є–µ 8 –љ–∞–і–Њ –Љ–µ–љ—П—В—М –љ–∞ CRC 00000000
    #text=orig[172..245]
    #text=orig[/(.<8>74455874.*?)49444154/,1][0..-9]

    #IDAT — 49444154
    #data=orig[246..-1]
    data=orig[/.<8>49444154.*/]

    #MAGIC COMMENT
    comment=Base64.decode64( «;background-image:url(data:image/png;base64;pzd,» ).unpack( «H*» ).to_s

    ###### OUTER PNG
    # «00000059» + «74455874» + «436f6d6d656e7400»
    # tEXt_length + ‘tEXt’ + ‘Comment.’
    # «3030» — two zero for base64 balance
    ###### INNER PNG
    # «00000008» + «74455874» + «436f6d6d656e7400» + «00000000»
    # min_tEXt_length + ‘tEXt’ + ‘Comment.’ + blank CRC
    #
    # CRC field one for two PNG ‘s
    # IE can’ t live without it, but others feel indifferently
    var =ihdr+ «00000059» + «74455874» + «436f6d6d656e7400» + «3030» +comment+ihdr+ «00000008» + «74455874» + «436f6d6d656e7400» + «00000000» +srgb_phys+data

    File .open( ‘out.png’ , ‘w’ )

    # CRC FIX
    puts «optipng -fix started. »
    `optipng -fix out .png`
    puts «optipng -fix completed»

    # MAKE STRING CSS READEABLE
    c= File .open( ‘temp’ , ‘r’ )<|f| f.read>.gsub(/backgroundimageurldataimage\/pngbase64pzd/, «;background-image:url(data:image/png;base64;pzd,» ).gsub(/\n/, «» )
    File .delete( ‘temp’ )

    # JUST PASTE TEXT FROM THIS FILE TO CSS
    File .open( ‘out_png64’ , ‘w’ )<|s| s.write( "#\);» )>

    * This source code was highlighted with Source Code Highlighter .

    MHTML

    —_
    Content-Type: text/css;

    */
    html, body <
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    >

    #half_logo <
    /*
    —_
    Content-Location:logo
    Content-Transfer-Encoding:base64
    Content-Type: image/png;*/

    */
    background-image: url(mhtml:http://192.168.1.2/test.css!logo) !ie;
    /*
    —_—
    */

    * This source code was highlighted with Source Code Highlighter .

    Тестировалось в FF 3.6, Opera 10.10, chromium, chrome, IE6-8

    Источник

    Оцените статью