Здравствуйте, народ, со светлыми зимними праздниками
Хочу реализовать такую штуку как вывод картинки(image/gif) в документ средствами javascript методами
document.open("image/gif"); document.write(str); и document.close();, но увы:
выводится лишь текст str, а не картинка.
Скрипты все что выкладываю писал в кодировке windows-1251, т.к. нужно чтобы были однобайтовые все символы по умолчанию.
Вот пример:
<html>
<head>
<script language="JavaScript">
Base64 = {
// private property
//алфавит кодировки base64
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
//отображение символов в с кодами >127 в кодировке w1251 в коды символов в кодировке utf-16be
w1251_to_utf16be:[1026, 1027, 8218, 1107, 8222, 8230, 8224, 8225, 8364, 8240, 1033, 8249, 1034, 1036, 1035, 1039, 1106, 8216, 8217, 8220, 8221, 8226, 8211, 8212, , 8482, 1113, 8250, 1114, 1116, 1115, 1119, 160, 1038, 1118, 1032, 164, 1168, 166, 167, 1025, 169, 1028, 171, 172, 173, 174, 1031, 176, 177, 1030, 1110, 1169, 181, 182, 183, 1105, 8470, 1108, 187, 1112, 1029, 1109, 1111, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103],
//преобразует число 0..255 в символ в кодировки документа w1251
f_numb_w1251_to_char_utf16be: function(c)//0<=c<=255
{
if(c<128) return String.fromCharCode(c);
return String.fromCharCode(this.w1251_to_utf16be[c-128]);
},
// public method for decoding
decode : function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + this.f_numb_w1251_to_char_utf16be(chr1);
if (enc3 != 64) {
output = output + this.f_numb_w1251_to_char_utf16be(chr2);
}
if (enc4 != 64) {
output = output + this.f_numb_w1251_to_char_utf16be(chr3);
}
}
return output;
}
};
function openImage(){
var b64="R0lGODlhCQAKAIABAOUCAv///yH5BAEAAAEALAAAAAAJAAoAAAIRjAOnuAbfXlISnjoRnjv1LxUAOw==";//красный треугольник в коде base64 строка такая же как и в m.php
var bytes=Base64.decode(b64);//получили строку из байт
document.getElementById('div').innerHTML=bytes;//можем проверить и сравнить при закоментированном header('Content-Type: image/gif'); в m.php
var w= open("about:blank", "displayWindow",
"width=500,height=400,status=0,toolbar=0,menubar=0");//открыли новое окно
//ps. всё удивляюсь: зачем нужен второй параметр "displayWindow" если он не работает как ссылка на созданное окно, а работает возвращаемое "w"
var d= w.document;//получили ссылку на docunent нового окна для вывода в него
d.open("image/gif", "replace");//на вывод-картинку
d.write(bytes);//пишем байты из которых состоит картинка
d.close();//не забываем закрыть вывод
};
</script>
</head>
<body>
<input type=button value="image" onclick="openImage();">
<div id='div'></div>
</body>
</html>
код картинки в переменной b64 в формате base64 можете проверить в скрипте, и увидеть что он выдает красный маленький треугольник в формате gif:
<?
$s='R0lGODlhCQAKAIABAOUCAv///yH5BAEAAAEALAAAAAAJAAoAAAIRjAOnuAbfXlISnjoRnjv1LxUAOw==';
$s=base64_decode($s);
header('Content-Type: image/gif');
echo $s;
?>
Вы можете закоментировать header и увидеть что выдаваемая абара-кадабра полностью совпадает с тем что выдается в появляющемся окошке, значит раскодирование с base64 происходит правильно не смотря на нетривиальность кода. Значит возможно дело в функционировании браузера, но я проверял на ie6, fairfox3, google chrome, и в opera под виндой икспи, и нигде картинка в появляющемся окне не отображается - только текстовое представление.
Значения массива w1251_to_utf16be - свойство объекта Base64 я получил из скрипта:
<?
//----------преобразует строку $str в массив с указанным типом $format и наоборот
//$format: С* - байт в виде цедого числа, И* - 32 битное целое число
// n* - целое беззнаковое 2-байтовое
function str_arType($str,$format){
$ar=unpack($format,$str);
array_unshift($ar,0);
array_shift($ar);
return $ar;
}
function arType_str($ar,$format){
array_unshift($ar,$format);
$str=call_user_func_array("pack",$ar);
return $str;
}
$str="";
for($i=0; $i<256; $i++)
{
$ar=array();
$ar[]=$i;
$s=arType_str($ar,"C*");
$s=iconv('WINDOWS-1251','UTF-16BE',$s);
$ar=str_arType($s,"n*");
echo $ar[0].", ";
};
?>
ps1:
Кстати, разрабатывая последний скрипт на получение массива, наткнулся на весьма неприятные вещи в php.
Он оказывается некорректно как-то конкатенирует строки представленные в кодировке utf-16be на текущей кодировки windows-1251, вот сам фокус:
<?
//----------преобразует строку $str в массив с указанным типом $format и наоборот
//$format: С* - байт в виде цедого числа, И* - 32 битное целое число
// n* - целое беззнаковое 2-байтовое
function str_arType($str,$format){
$ar=unpack($format,$str);
//чтобы не было текстовых ключей начинающих отчет с "1"
array_unshift($ar,0);// вставляем в начало массива - массив преобразуется в список(массив с всегда отсортированными по возрастанию числовыми ключами)
array_shift($ar);//удаляем вставленный для преобразования элемент
return $ar;
}
function arType_str($ar,$format){
array_unshift($ar,$format);//преобразуем в массив с параметрами для вызова функции pack
$str=call_user_func_array("pack",$ar);
return $str;
}
//--------------------
// фокус номер 1
$a=array();
for($i=0; $i<256; $i++)
{
$a[$i]=$i;
};
$s=arType_str($a,"C*");
echo strlen($s)."<br>\n";//всё верно 256
$s=iconv('WINDOWS-1251','UTF-16BE',$s);//по идее размер должен быть увеличен вдвое
echo strlen($s)."<br>\n";//почему-то выдает не 512, а 304!!!!
// фокус номер 2
$str="";
$ars=array();
for($i=0; $i<256; $i++)
{
$ar=array();
$ar[]=$i;
$s=arType_str($ar,"C*");
$s=iconv('WINDOWS-1251','UTF-16BE',$s);
echo "$i ".strlen($s)."<br>\n";//везде по 2 байта(2 w1251 cимвола) на utf-16be символ, всё верно
$str.=$s;//прилепливаем к строке 1 вариант соединения
$ars[]=$s;//откладываем в массив 2 вариант соединения
};
echo strlen($str)."<br>\n";// по 1 варианту получаем не 512 а 510!!!
echo strlen(implode('',$ars))."<br>\n";//просто сливаем двухбайтовые строчки массива в одну. по 2 варианту получаем не 512 а тоже 510!!!!!!
?>
Может кто найдет этому объяснение? исходная кодировка windows-1251 как я уже говорил... я пока думаю эта нелепица происходит из за управляющих символов, которые, находясь по соседству в строке пожирают друг друга или сливаются.. другого объяснения не вижу.
ps2:
А начиналось всё с того что я решил освоить VRML, и там я набрел на такую
ссылку: но итоговый код не заработал, тоже выдавался текст вместо трехмерного кубика. Однако проигрыватель vrml у меня установлен, их даже два у меня:
кортонка и
флукс-плейр
в отдельном файле *.wrl этот представленный куб отображается, а вот выводится в новое окно не хочет, отображается и в окне браузера.. вообщем много тщетно бился, думая что это уже устаревшие стандарты все возможные миме типы попробывал: //x-world/x-vrml, model/vrml,x-world/vrml,application/x-cortona,model/fx3d.
Потом я сделал предположение, что может вывод путем open+write+close в современных браузерах просто напросто не поддерживает mime типы отличные от text/html и text/plain(последний кстати не работает в google chrome почему-то, я проверял). Вот и решил проверить своё предположение на примере с gif маленькой, но заметной картинкой. Увы похоже моё предположение подтверждается..
или у современных браузеров есть другие средства для реализации данного действия?