Девятый бит: Блог кафедры АСОИУ ОмГТУ

htmlZclip: Возвращение копирования текста с форматированием в Оперу

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

И тогда обнаружил, что оно не работает с новой версией Оперы :cry:

Зайдя на страничку автора (A.Ruzanov — Lex1), и прочитав комментарии к htm2clip, понял, что новую версию ждать придется долго (похоже автор ее забросил).

Так и родился htmlZclip.
Основные его преимущества перед  htm2clip:

  • работает на новых версиях Оперы
  • делает это в 1,7 раз быстрее

Мне от htm2clip нужна была только функция копирования (вставкой не пользовался), поэтому htmlZclip может только копировать (форматированной вставки нет).

скачать\ Download /download

Установка

Ставится он практически также, как и htm2clip. Нужно скопировать 2 файла, и прописать в браузере MIME тип.

  1. скачиваем
  2. копируем из архива файл ‘copy\htmlZclip.exe‘ в
    <путь к папке с установленной оперой>\program\
    (обычно ‘htmlZclip.exe’ нужно копировать в
    C:\Program Files (x86)\Opera\program\‘ – для 64bit систем, либо,
    если такого пути нет, то в ‘C:\Program Files\Opera\program\‘ – для 32bit)
  3. теперь выделим следующую строку:
    opera:config#UserPrefs|MenuConfiguration
    нажмем Ctrl+C затем Ctrl+Shift+V
    и получим путь (в первой строчке) к месту, куда надо скопировать из архива файл ‘copy\standard_menu.ini
    обычно ‘standard_menu.ini’ нужно копировать в
    C:\Users\<имя пользователя>\AppData\Roaming\Opera\Opera\menu\‘ предварительно создав отсутствующую папку menu
  4. нажмем Ctrl+F12 , откроем вкладку ‘Расширенные‘, зайдем в ‘Загрузки‘ (слева), нажмем кнопку ‘Добавить…‘,
    в появившемся окне указываем в поле MIME-тип text/htmlZclip
    выбираем Действие Открыть в другой программе:, и вписываем в поле строку program\htmlZclip.exe
    далее жмем кнопку OK, и снова OK

Всё, теперь нужно перезагрузить Оперу, и можно копировать текст с форматированием (в контекстном меню выделенного текста появится пункт ‘Copy with format‘).

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

Допиливаем установку

Я не буду здесь говорить, что копируя мой ‘standard_menu.ini’ вы могли затереть свою менюшку, и что лучше вместо этого вставить новый элемент в свое меню. Раз вы это читаете, вам это должно быть известно.

В этом разделе я бы хотел сказать, например, то, что кидая к себе ‘htmlZclip.exe’ и прописывая к нему MIME, вы проделываете в своем браузере приличную дырку отбойным молотком. Если оставить все как есть, то браузер, встретив на любом сайте объект с MIME text/htmlZclip, сразу отошлет его в ‘htmlZclip.exe’, а тот, в свою очередь, поместит его в буфер обмена…

Чтоб этого не случилось, достаточно заменить MIME на какую-нибудь ерунду, например text/trali-vali;eli;sandali. MIME следует заменить в браузере и в скрипте (он прописан в начале скрипта, можно найти поиском; ваш К.О.) в ‘standard_menu.ini’.

Можно прописать клавиатурное сокращение в секцию Application своего ‘standard_keyboard.ini’, например для сочетания Ctrl+Alt+C:

...
[Application]
...
c ctrl alt="Go to page, "javascript:(function(){...
...

Либо прописать то же самое в GUI: Расширенные настройки -> Управление. Только не забудьте удалить внешние кавычки.

Исходники

В директории ‘src\‘ архива находятся все исходники. Исходники содержат шапку, в которой указана их версия
(формат — ‘htmlZclip v<версия оперы>.<номер версии htmlZclip для данной версии оперы>’), а также даны все необходимые ссылки:

Вначале стоит посмотреть, что именно заносится в буфер обмена при копировании, например в IE:

Затем лучше почитать описание на MSDN точное описание формата заголовка HTML Clipboard Format (CF_HTML).

Далее можно посмотреть несколько реализаций копирования в буфер обмена CF_HTML:

И в конце следует взглянуть на некоторые WinAPI для работы с буфером обмена (там особенно ценны комментарии):

htmlZclp.js

Этот код, после упаковки в YUI Compressor переносится в ‘standard_menu.ini’.

Все основные действия происходят в нем, и, в отличии от htm2clip, здесь же, на JavaScript, формируется полный заголовок для CF_HTML. Что касается всего остального, то смотрите исходники, понять их несложно.

encodeBase64full

В исходнике спрятано (закомментировано) пасхальное яйцо — самая быстрая реализация кодирования в Base64 на JavaScript в Опере. Вы можете на досуге сами сравнить мою реализацию с предыдущей самой быстрой реализацией, которая, кстати от того же автора (A.Ruzanov).

htmlZclip.exe

Здесь делается как раз то, что нельзя сделать в браузере на JavaScript, — скопировать в буфер обмена с указанием формата CF_HTML. Вот и все, больше ничего оно не делает, так как формирование заголовка CF_HTML было перенесено на JavaScript.

Оно написано на C,  и в собранном виде занимает 3 072 байа, в отличии от htm2clip — Delphi и 14 336 байт.

В архиве находится целиком весь проект, созданный в Visual Studio 2010 с использованием Windows SDK 7.1 (задается в свойствах проекта — ‘Platform Toolset’).

Если загляните в файл ‘htmlZclip.c’, то в середине функции wWMain увидите забавную конструкцию, начинающеюся с ‘(hText =‘. Предлагаю самостоятельно разобраться с тем, как она работает, и лишь скажу, что это очень удобный способ проверки отработки WinAPI функций.

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

Если же вы считаете себя параноиком, то смело переписывайте нормально этот участок кода, дополнив его недостающими проверками, дополнительными циклами и сообщениями пользователю, что проге стало плохо. Ах да, чуть не забыл, еще можете для успокоения души убрать _GS_CHECK_OFF.

Как это работает

После формирования CF_HTML (данных согласно этому формату), он передается в виде DataURL в качестве src новому iframe.

Далее браузер, видя появление нового объекта, по MIME определяет что ему делать. В нашем случае браузер создает в директории для временных файлов новый файл и записывает в него наш CF_HTML. Затем путь к временному файлу передается в ‘htmlZclip.exe’ в качестве опции запуска.

И, в конце, ‘htmlZclip.exe’ переписывает содержимое временного файла в буфер обмена с указанием формата ‘HTML Format‘.

За кадром

Google & сжатие JS

JavaScript я пробовал сжимать разными оптимизаторами/компрессорами, в этом помог compressorrater.thruhere.net, но особенно мне запомнился Google Closure Compiler. Попробуем в нем ‘сжать’ следующий код в режиме Simple или Advanced:

alert(function(){var z="мая любить копировать ::-)";return z[1]+z[1]+z[3]+z[4]+z[6]+z[10]+z[1]+z[8]+z[2]+z[5]})

И вот что получим :lol: :

Original Size:	130 bytes (121 bytes gzipped)
Compiled Size:	1.27KB (135 bytes gzipped)
		Saved -898.46% off the original size

Пути JIT-компиляции неисповедимы

Вначале я не планировал переносить формирование заголовка CF_HTML на JavaScript, боясь увеличить время выполнения. Это коренным образом изменилось после того, как сравнил скорость работы готового ‘htmlZclip.js’ с htm2clip, и получил, что JavaScript htmlZclip’а работает в 1,6 раз быстрее, чем JavaScript htm2clip’а.

Решив, что изменение кода для формирования заголовка CF_HTML не сделает htmlZclip медленнее, чем htm2clip, стал менять код. Каково же было мое удивление, когда новый ‘htmlZclip.js’ стал работать на 8% быстрее, чем старый  8-O. Видать, не зря, когда его модифицировал, постоянно думал о производительности.

Подпись файла размером с сам файл

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

В этот раз мне этого делать не захотелось. Посудите сами, файл ‘htmlZclip.exe’ размером 3 КБ, после подписывания со штампом времени стал весить 8 КБ.

Из-за чего htm2clip перестал работать

Чтоб лучше это понять, вначале нужно прочитать эту статью: Исследуем скорость выполнения JS и алгоритм отображения страниц, а также этот комментарий.

Часто ради оптимизации пользуются определенными особенностями, пологая, что эти особенности далее останутся неизменными. Вот наглядный пример такой особенности: посмотрим на конец JavaScript’а оригинального htm2clip:

doc.documentElement.appendChild(f);f.parentNode.removeChild(f)}})();

Здесь видно, что добавленный только что объект сразу удаляется. В старой Опере выполнение данной конструкции было реализовано не очень эффективно и приводило к перерисовке. В новой версии Оперы убрали этот недостаток.

Но постойте, отсутствие отрисовки означает, что не появится новый объект, и дальше ничего работать не будет (см. выше Как это работает). Поэтому в htmlZclip предположение об обязательной отрисовки я заменил на предположение о том, что отрисовка точно должна произойти за 5 секунд:

setTimeout(function(){
object.parentNode.removeChild(object);
object=null;},5000);

Вообще, работать будет даже если поставить 0 мс, я просто даю небольшую передышку. Кстати, теперь если несколько раз использовать это копирование, то можно наблюдать в определенной части страницы некое подобие прогресс-бара из небольших iframe’ов  ;-) , каждый из которых будет исчезать через 5 сек.

  • Кто бы еще перевел эту статью на EN. Есть желающие?

  • Обновление:
    ‘htmlZclip.exe’ теперь минимально подписан, и весит 4 КБ

  • спасибо за программу, пытался настроить, но пока не получилось.
    Обьясните попроще работает ли она на 11.51, как пользоваться копированием в клипборд, и копирует она рисунки в word или куда то в другое место?

  • > Вы можете на досуге сами сравнить мою реализацию

    Похоже это зависит от того как измерять ^_^ http://rghost.ru/23168061

    «convertStringToBase64: 24 ms
    encodeBase64: 16 ms
    Base64.encode: 24 ms
    encodeBase64full: 194 ms
    encodeBtoa: 12 ms»

    > Здесь видно, что добавленный только что объект сразу удаляется.

    Примерчик на эту тему:
    javascript:
    var fr=document.createElement(‘iframe’);
    fr.src=»javascript:alert(»)»;
    document.documentElement.appendChild(fr);
    fr.parentNode.removeChild(fr);
    void(0);

    Не работает в фоксе, работает в остальных браузерах.

  • Пардон это было в фоксе. В опере:
    convertStringToBase64: 71 ms
    encodeBase64: 30 ms
    Base64.encode: 58 ms
    encodeBase64full: 58 ms
    encodeBtoa: 31 ms

  • 2qwe:
    > работает ли она на 11.51
    Да

    > как пользоваться копированием в клипборд
    Выделяешь нужное место, жмешь правую кнопку мыши, жмешь «Copy with format»

    > копирует она рисунки в word
    Да. При выделении, рисунок должен попасть в выделенную область

  • >> Здесь видно, что добавленный только что объект сразу удаляется.

    >Примерчик на эту тему:
    javascript:
    var fr=document.createElement(‘iframe’);
    fr.src=»javascript:alert(»)»;

    естественно, это же алерт
    >> Вы можете на досуге сами сравнить мою реализацию
    >Похоже это зависит от того как измерять ^_^
    точнее на чем измерять: http://jsperf.com/encodebase64full
    Opera 11.51:
    encodeBase64full 173 ±2.01% fastest
    encodeBase64 134 ±1.00% 23% slower
    convertStringToBase64 66.50 ±0.90% 62% slower
    Base64.encode 73.87 ±1.11% 57% slower
    encodeBtoa 152 ±1.26% 12% slower
    У сейчас Оперы проблемы с отправкой результатов.

  • Воткнул в старую тестовую страницу вашу строку и encodeBase64full победил и там:
    convertStringToBase64: 14 ms
    encodeBase64: 6 ms
    Base64.encode: 11 ms
    encodeBase64full: 4 ms
    encodeBtoa: 5 ms

    Но вот после учетверения строки, результаты изменились:
    convertStringToBase64: 51 ms
    encodeBase64: 22 ms
    Base64.encode: 40 ms
    encodeBase64full: 42 ms
    encodeBtoa: 21 ms

    Любопытный эффект.

    > естественно, это же алерт

    Но фрейм таки создаётся. И подход при котором javascript: выполняется, а data: — нет, выглядит не слишком логичным.

  • > Любопытный эффект.
    Да. Я приводил тест зависимости скорости от объема текста http://my.opera.com/Lex1/blog/fast-base64-encoding-and-test-results#comment63283502

    (encodeBase64full|encodeBase64|chars number)
    (5 ms|7 ms|22437)
    (12 ms|16 ms|60416)
    (18 ms|22 ms|92904)
    (44 ms|30 ms|112185)
    Обычно копируемая область небольшая (содержит мало текста + весь css), поэтому для htmlZclip такой вариант хорошо подходит.

    > И подход при котором javascript: выполняется, а data: – нет, выглядит не слишком логичным
    Особенности реализации, для data с особым MIME нужно вызвать внешнюю программу (долго), а JavaScript всегда под рукой.

  • ZKyl
    у меня не копирует ничего даже в блокнот, вы не могли бы залить готовый вариант с использованием opera-usb.com/operausben.htm? тогда будет проще затестить, спасибо.

  • >у меня не копирует ничего даже в блокнот
    Да, в блокнот он не копирует, ибо незачем.
    Копирует в Microsoft Word, LibreOffice Writer…
    а также в WYSIWYG-HTML редакторы ( http://www.tinymce.com/tryit/full.php ), открытые в других браузерах.
    >вы не могли бы залить готовый вариант
    http://narod.ru/disk/27304862001/Opera%2BhtmlZclip.7z.html
    >opera-usb.com/operausben.htm
    Стандартный установщик оперы уже несколько версий как поддерживает создание Portable версии.

  • спасибо, если будет норм. работать в новой версии, то будет включен в сборку my.opera.com/recheck

  • и ещё вопрос:
    есть скрипт, он тоже копирует в word с картинками
    http://paste.pocoo.org/show/494137/
    вопрос: у вас получше будет?

  • >http://paste.pocoo.org/show/494137/
    >вопрос: у вас получше будет?
    Да, htmlZclip может скопировать целый кусок страницы (сохраняя фон элементов, структуру…), а «document.designMode=’on’» копирует меньше (без фона, без структуры…).

  • Всё заработало. Но большое огорчение. Не работает (не вставляется) в WinOrganizer, который у меня лицензилонный и который для меня незаменимая вещь. А старый htm2clip прекрасно работал (((

  • И ещё в старой версии оперы работал autocopy.js из той же сборки. Теперь нет. Снова печаль.

  • > Не работает (не вставляется) в WinOrganizer…
    > А старый htm2clip прекрасно работал
    Вставлял с форматированием?
    В одной папке с htm2clip.exe находился htmltortf.dll ?
    > И ещё в старой версии оперы работал autocopy.js
    Если надо, то это можно устроить. IMHO назначить горячие клавиши на копирование с форматированием лучше, чем на каждую страницу повесить UserJS (autocopy.js)

  • Да, естесственно, вставляла с форматированием. Первый раз слышу об htmltortf.dll. В архиве с прогой нету.
    С autocopy.js мне было удобно, т.к. приходится очень много копировать. Придется искать любиомй Опере замену. могли же, наконец, разработчики и сделать эту мелочь.

  • P.S. Нашла на просторах инета данную dll. Всё равно в WinOrganizer не вставляет. Просто не активен НИКАКОЙ пункт вставки — ни обычная, ни спец, ни чистый текст. Как будто буфер обмена пустой. (В Ворд вставляет).

  • Дальнейшие поиски проблемы копирования с форматированием привели к расширению «Edit the Page». С его помощью можно это делать. Но приходится включать/выкючать его даже для масштабирования страницы, т.е. вместо масштабирования начинают писаться —+++.

  • Обновление:
    Теперь работает вставка в любую программу, качество вставленного фрагмента зависит от самой программы (в Word… вставляет как и раньше, в notepad — просто текст).

    Точнее в него добавилось копирование из http://paste.pocoo.org/show/494137 (и «Edit the Page») для программ, в которых раньше ничего не вставлялось.

    2Tarnakko: могу исправить autocopy.js, чтоб он работал с htmlZclip, но копировать в WinOrganizer он не сможет (только Word…). Такой autocopy.js нужен?

  • Наверное такой autocopy.js будет неполноценным. И лично для меня не совсем нужным. Остальное протестируем.

  • Проверенно на версии 11.60 — работает, можно спокойно обновлять.

  • >> могу исправить autocopy.js, чтоб он работал с htmlZclip

    Можно ли сделать это?
    В Опере очень не хватает простого автокопирования выделенного текста!
    Спасибо.

  • ZKyl
    Большое спасибо за оперативность.
    скрипт скачал, программу настроил.
    К сожалению, не работает :(

    Проверял на 11.01, 11.52 и 11.60
    После выделения текста на неск. секунд появляется прогресс-бар (явно что-то происходит), но текст в буфере не появляется.

    Тип файла: text/htmlZclip
    Расширение: нет
    Действие: открыть в программе «E:\Opera\program\htmlZclip\htmlZclip.exe» (галка «передавать адрес» не установлена).
    Путь к папке userjs: e:\Opera\profile\userjs\

  • 2hermit,
    В Word надо вставлять «с сохранением исходного форматирования»: http://office.microsoft.com/ru-ru/word-help/HA010215708.aspx

    Еще можно попробовать прописать точный путь к userjs: e:\Opera\profile\userjs\autocopy.js

  • ZKyl,
    ещё раз спасибо.

    Я имел ввиду простое автокопирование выделенного текста в буфер обмена, без сохранения форматирования для Word etc.

    Прописать полный путь к скрипту невозможно; указывается ведь путь к папке ujs-скриптов.

    Видимо, придётся просто отвыкнуть от этой удобной фичи.

    Кстати, частичный workaround для сохранения форматирования: есть скрипт view-selection-source.js
    (показывает выделенный фрагмент в html-формате).

  • использование утилиты от 31.10.2011 и нового пункта меню, взятого отсюда htmlZclip.7z\copy\standard_menu.ini, выдает вот такой результат
    [URL=http://s2.ipicture.ru/Gallery/Viewfull/9381332.html][IMG]http://s2.ipicture.ru/uploads/20120321/thumbs/0BAZthTM.jpg[/IMG][/URL]
    при возврате прежнего пункта меню баг пропадает, пробовал на разных версиях оперы. что можете посоветовать?

  • Kiril__777,
    Скорее всего Вы ранее следуя совету из раздела «Допиливаем установку» сменили MIME «text/htmlZclip» на свой.
    В новом standard_menu.ini MIME — стандартный («text/htmlZclip»), поэтому Вам опять надо заменить его на свой вариант.

  • ZKyl, спасибо за наводку

  • Kiril__777
    спасибо работает отлично и что очень приятно быстро! Правда замена standard_menu.ini — не очень хороший вариант, файл хранит огромное кол-во настроек (100 Кб), в описании, наверное, лучше указать, мол найти в собственном standard_menu.ini строку [Hotclick Popup Menu] и в ниже опций copy вставить ваш блок.

    Хотел поинтересоваться, а можете сделать кнопку «Копировать в Evernote»? Его стандартное приложение копирует из оперы есесно без форматирования.

  • ZKyl, совсем недавно появился вопросец:
    нельзя ли научить htmlZclip.exe копировать текст при выделении так, чтобы потом можно было вставить его в блокнот?

    все остальное отлично работает :)

  • Извините за задержку, готовился к защите диссертации.

    ILija,
    > Правда замена standard_menu.ini – не очень хороший вариант, файл хранит огромное кол-во настроек (100 Кб)
    - он (на 100 Кб) находится в «C:\Program Files\Opera\ui», а в инструкции заменяется пользовательское меню в «C:\Users\\AppData\Roaming\Opera\Opera\menu\».
    >в описании, наверное, лучше указать, мол найти в собственном standard_menu.ini строку [Hotclick Popup Menu] и в ниже опций copy вставить ваш блок.
    Это написано в начале раздела «Допиливаем установку».

    >Хотел поинтересоваться, а можете сделать кнопку «Копировать в Evernote»? Его стандартное приложение копирует из оперы есесно без форматирования.
    Не пользовался Evernote, всегда хватало встроенного «Копировать в заметки». Лучше обратитесь к разработчикам Evernote со ссылкой на htmlZclip.

    Kiril__777> нельзя ли научить htmlZclip.exe копировать текст при выделении так, чтобы потом можно было вставить его в блокнот?
    Это появится в следующей версии. Думаю достаточно будет в htmlZclip.с заменить RegisterClipboardFormatW(L»HTML Format») на CF_UNICODETEXT, а в autocopy.js заменить outerHTML на outerText

  • Уважаемый ZKyl, на днях вышла Опера 12.1 и в ней больше не работает ваша чудесная примочка :`(

  • Извините за беспокойство, решения так и не нашлось?

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

  • Огромное вам спасибо! Работает приотлично! У меня вставляет ваш скрипт во все используемые мною программы и в частности в evernote с урлом источника с картинками в самом тексте и форматированием! Ура!

    А может вы опубликуете эту тему на Хабре? Есть отдельная тема по Опере и в комментах люди часто задаются вопросом копирования с форматированием.

  • К сожалению я на Хабре не зареген.

  • Здравствуйте! Не ругайте слишком. Есть вопрос. Точнее может ли кто то обьяснить доступно этот абзац:
    Чтоб этого не случилось, достаточно заменить MIME на какую-нибудь ерунду, например text/trali-vali;eli;sandali. MIME следует заменить в браузере и в скрипте (он прописан в начале скрипта, можно найти поиском; ваш К.О.) в ‘standard_menu.ini’.
    Не понял что такое К.О. и какую строчку менять, искал пару часов. Обьясните пожалуйста, что и где менять. Спс

  • А работает четко автор молодец!!! Жду ответа на вопрос выше!

  • К сожалению Opera, которую мы знаем скоро перестанет существовать: http://habrahabr.ru/company/opera/blog/169239/

    >какую строчку менять
    MIME надо изменить в copy\autocopy.js
    в самом начале файла: document.addEventListener(‘mouseup’, function(){(function(){var b=function(t,q,s){var B=’text/htmlZclip’;var
    htmlZclip — надо заменить на что-то своё.

    в copy\standard_menu.ini
    чуть ниже начала: Platform Windows, Item, «Copy with format»=Go to Page, «javascript:(function(){var b=function(t,q,s){var B=’text/htmlZclip’;var
    опять же htmlZclip — надо заменить на своё значение.

    И в 4-ом пункте установки:
    нажмем Ctrl+F12 , откроем вкладку ‘Расширенные‘, зайдем в ’Загрузки‘ (слева), нажмем кнопку ‘Добавить…‘,
    в появившемся окне указываем в поле MIME-тип text/htmlZclip…
    опять htmlZclip — заменить на своё значение.

    >Не понял что такое К.О.
    http://zhgun.ru/cap/saying/13717745.png

  • Спасибо огромное ZKyl. Все помогло.

You must be logged in to post a comment.