Создание встроенного изображения с помощью java gwt

Я пытаюсь написать встроенное изображение с помощью Java GWT. Однако изображение не отображается:

<img src="data:unknown;base64,Pz9QAQSkZJRgABAQAAAQABAA9Q9AAUDBAcJCggFBQkGCAYGBggFBQUFCAgGBQYGBwUHBwUGBgUHChALBwgaCQUFDBUMDhERHxMfBxciGBYSGBAeEx4BBQUFCAcIDwgJCBIIDA4SEhISEhISEh4SEhIeEhIeHhISEh4eEhIeHh4SHh4eEhISEhISHh4eEhIeEh4eEhISHfz9ABEIAGAAYAMBIgACEQEDEQD9QAcAAACAQUBAAAAAAAAAAAAAAAAAQcCAwQGCAT9QAvEAACAQIEBAMHBQAAAAAAAAAAAQIDEQQFEiEGBzFBE1FyIjJhYnD9RRSPz9P0AGwEBAAIDAQEAAAAAAAAAAAAAAAECBAUHBgL9QAgEQEAAgEFAAMBAAAAAAAAAAAAAQIDBAUREiETMmExP0ADAMBAAIRAxEAPw9M0zKv1jbfz9bP0SUlJdkZtD0RV4JeRluEP0jP0tP0URVGNiorZSf9R9MP0dT0aVH9RznWgcfz9M379RET9Pz9GXo/EzNuW1FYUv9SXN1Wfz9Dj8/UpcHP05RjsQVM2S9XPz9Rf9Vb9Pz9SxxVL9JpDcWoNRzxuXYQXAYmFwAZV79WNiOfz9JX4vZEY8XoyPz9EnR6Lvz9X8PPz9My9vVv9P00c0lyRl8dOz9Ogr9P1GP0RBcG4YS79P07MF9dv09P1fRxwWk6R0hpLPz9XP1/Ux80cv1bf0CPz9OxH9UFwAP1qR3H9TP0CJg/Ffz9Pz9TlYVSkpxS39WL9S0T9a04cm8cZX4NSU39P0XEv0+1r9TPz9Pz9P1TTw9aEpWTv06Nfz9VP07NFn9cM3fF1eP1GAzRzP0hL0wSX9X04Jg5aZSL9P1rWr9Yv1fEi5ZOv1zMf0ND2UjJfz9Pz9HnZ9VoqFPymIPz9af1yD2QOIWJGP1ZQf1NXdmQBxXP0SUfz9P11aP0tMjv9SUpP1/Rf1BP1NTD9Yz9Pz9TT9X9HvX9XSwiT1sQT9NTT9W0zbv0mXv06P0ZP1RSfz9Rb9f0ADExgVQYAABcBDQ9cTH9Fgb9Sy79YzsPS0l8GE8gQAEAYCAYAAAAAAAAAPz9">

Мне кажется, что причина этого в том, что я неправильно кодирую его с помощью base64 или что кодировка неверна.

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

<img src="data:unknown;base64,R0lGODlhDwAPAKECAAAAzMzM/////wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLlN48CXF8m2iQ3YmmKqVlRtW4MLwWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw==">

Вот как я генерирую свой пик-код. Я открываю URL-адрес и пытаюсь закодировать результат в base64:

try {
    IoProvider.get().makeRequestAsText(url,
        new ResponseReceivedHandler<String>() {
          public void onResponseReceived(ResponseReceivedEvent<String> event) {
            final Response<String> response = event.getResponse();
            if (response.getStatusCode() == HTTP_OK){
            callback.onSuccess("data:unknown;base64,"
                + Base64.encode(response.getText()));
            }
          }
        }, options);
} catch ...

Я использую кодировщик base64: http://snipt.net/tweakt/gwt-base64/

Любые идеи, почему сгенерированное изображение недействительно?

РЕДАКТИРОВАТЬ:

Я немного переписал свой код, основываясь на ваших ответах. Вот как это выглядит сейчас:

IoProvider.get().makeRequest(url,
  new ResponseReceivedHandler<Object>() {
    public void onResponseReceived(ResponseReceivedEvent<Object> event) {
      final Response<Object> response = event.getResponse();
        if (response.getStatusCode() == HTTP_OK) {

          // not working
          callback.onSuccess("data:image/jpeg;base64,"
              + Base64Utils.toBase64(response.getText().getBytes()));

          // working image
          // callback.onSuccess("data:unknown;base64,R0lGODlhDwAPAKECAAAAzMzM/////wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLlN48CXF8m2iQ3YmmKqVlRtW4MLwWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw==");
        }
      }
}, options);

Отредактированный код производит следующий код:

<img src="data:image/jpeg;base64,77+977+977+977+9ABBKRklGAAEBAAABAAEAAO+/ve+/vQDvv70ABQMEBwkKCAUFCQYIBgYGCAUFBQUICAYFBgYHBQcHBQYGBQcKEAsHCBoJBQUMFQwOEREfEx8HFyIYFhIYEB4THgEFBQUIBwgPCAkIEggMDhISEhISEhISHhISEh4SEh4eEhISHh4SEh4eHhIeHh4SEhISEhIeHh4SEh4SHh4SEhIe77+977+9ABEIAGAAYAMBIgACEQEDEQHvv73vv70AHAAAAgEFAQAAAAAAAAAAAAAAAAEHAgMEBggF77+977+9AC8QAAIBAgQEAwcFAAAAAAAAAAABAgMRBAUSIQYHMUETUXIiMmFice+/ve+/vRRS77+977+977+977+977+9ABsBAQACAwEBAAAAAAAAAAAAAAABAgQFBwYD77+977+9ACARAQACAQUAAwEAAAAAAAAAAAABAgMEBRESIRMyYTHvv73vv70ADAMBAAIRAxEAPwDvv70w77+9Myvvv71jbu+/ve+/vcWt77+9Eu+/vUlJdkZtDO+/vRHvv71eyIl5GW4R77+9I++/ve+/vS3vv73vv70U77+9FUY2KitlKO+/ve+/vRDvv70x77+9HUzvv70a77+9Uu+/vUTvv73Hp++/vWgc4a+m77+977+9M3/vv71ERe+/ve+/ve+/ve+/vRl6PxMzbu+/vW1FYUzvv71Jc3Va77+977+9Dj8/77+9Slwd77+9OUY7EO+/vVM277+9L1fvv73vv73vv73vv70Y77+977+9V++/ve+/ve+/ve+/ve+/vSxx77+9U++/ve+/vdKaQ3FqDUc8bu+/vXYQXAYmFwAZ77+9X++/ve+/vWNiOu+/ve+/vSV+L2RGPO+/vXoy77+977+977+9EnR6L++/ve+/ve+/vX8P77+977+977+9My9v77+9XO+/ve+/ve+/vTRzSXJGXx0477+977+9Ogvvv73vv73vv71GP0RB1bBuGO+/vS/vv73vv73vv707MFDvv71377+9Pe+/ve+/vV/vv70ccO+/vWnnrLpHSGkt77+977+9Xe+/vX9THzRz77+9W86y77+9Au+/ve+/ve+/vTsS77+977+9QXAB77+9akdy77+9Te+/vQLvv73GmD8W77+977+977+977+977+9TlYVSkpx77+9Lu+/ve+/vWPvv71LRe+/vWjvv704cm8cZX4NSU7vv73vv73vv70XE++/vT7Oq1vvv71N77+977+977+977+977+977+977+9U++/vTw9aEpWT++/vTo277+977+9Ve+/vTs0Wu+/vXHPjtufFO+/vV7vv73vv71GAzRz77+977+9ISzvv70w77+9Ju+/vVzvv704Jg5aZSPvv73vv73vv71ry6Fr77+9Y++/vV8SLlk777+9czLvv70ND2UjJu+/ve+/ve+/ve+/ve+/vR52fe+/vVoqFe+/vcKmIe+/ve+/vWrvv71yD2QOIWJG77+977+9WULvv71N77+9d2ZAHFfvv73vv70SUu+/ve+/ve+/ve+/vXVp77+9LTI877+977+9JSnvv73vv71/Ru+/vUHvv73vv71N77+9Me+/vWDvv73vv73vv73vv73vv73vv70177+977+9cO+/vR/Dtu+/vV0sIu+/vT1s77+9Be+/vTU177+9WO+/vTNv77+9Jl/vv70677+977+9Ge+/ve+/vVFK77+977+977+9F++/vXzvv70ADExgVQYAABcBDQDvv71xMu+/vRYH77+9Sy/vv71jOw9LSXwYTyBAAQBgIBgAAAAAAAAB77+977+9">

Я также попытался преобразовать кодировку:

try {
  callback.onSuccess("data:image/jpeg;base64,"
    + Base64Utils.toBase64(response.getText().getBytes("ISO-8859-1")));
} catch (UnsupportedEncodingException e) { }

Что производит этот код:

<img src="data:image/jpeg;base64,/f39/QAQSkZJRgABAQAAAQABAAD9/QD9AAUDBAcJCggFBQkGCAYGBggFBQUFCAgGBQYGBwUHBwUGBgUHChALBwgaCQUFDBUMDhERHxMfBxciGBYSGBAeEx4BBQUFCAcIDwgJCBIIDA4SEhISEhISEh4SEhIeEhIeHhISEh4eEhIeHh4SHh4eEhISEhISHh4eEhIeEh4eEhISHv39ABEIAGAAYAMBIgACEQEDEQH9/QAcAAACAQUBAAAAAAAAAAAAAAAAAQcCAwQGCAX9/QAvEAACAQIEBAMHBQAAAAAAAAAAAQIDEQQFEiEGBzFBE1FyIjJhYnH9/RRS/f39/f0AGwEBAAIDAQEAAAAAAAAAAAAAAAECBAUHBgP9/QAgEQEAAgEFAAMBAAAAAAAAAAAAAQIDBAUREiETMmEx/f0ADAMBAAIRAxEAPwD9MP0zK/1jbv39bf0S/UlJdkZtDP0R/V4JeRluEf0j/f0t/f0U/RVGNiorZSj9/RD9Mf0dTP0a/VL9RP3n/Wgc5v39M3/9REX9/f39GXo/EzNu/W1FYUz9SXN1Wv39Dj8//UpcHf05RjsQ/VM2/S9X/f39/Rj9/Vf9/f39/Sxx/VP9/ZpDcWoNRzxu/XYQXAYmFwAZ/V/9/WNiOv39JX4vZEY8/Xoy/f39EnR6L/39/X8P/f39My9v/Vz9/f00c0lyRl8dOP39Ogv9/f1GP0RBcG4Y/S/9/f07MFD9d/09/f1f/Rxw/Wk6R0hpLf39Xf1/Ux80c/1bsv0C/f39OxL9/UFwAf1qR3L9Tf0C/Zg/Fv39/f39TlYVSkpx/S79/WP9S0X9aP04cm8cZX4NSU79/f0XE/0+q1v9Tf39/f39/f1T/Tw9aEpWT/06Nv39Vf07NFr9cc7fFP1e/f1GAzRz/f0hLP0w/Sb9XP04Jg5aZSP9/f1r4Wv9Y/1fEi5ZO/1zMv0ND2UjJv39/f39HnZ9/VoqFf2mIf39av1yD2QOIWJG/f1ZQv1N/XdmQBxX/f0SUv39/f11af0tMjz9/SUp/f1/Rv1B/f1N/TH9YP39/f39/TX9/XD9H/b9XSwi/T1s/QX9NTX9WP0zb/0mX/06/f0Z/f1RSv39/Rf9fP0ADExgVQYAABcBDQD9cTL9Fgf9Sy/9YzsPS0l8GE8gQAEAYCAYAAAAAAAAAf39">

Как я могу передать ответ кодировщику Base64, не преобразовывая его в строку?

response.getData() — это объект, и мне нравится использовать его как byte[].


person JochenJung    schedule 20.06.2011    source источник
comment
Я обошел это и теперь пробую некоторые альтернативные идеи: если у клиента есть URL-адрес изображения, есть ли причина для его встраивания с использованием кодировки base64 вместо динамического обновления URL-адреса объекта изображения?   -  person maasg    schedule 01.07.2011
comment
Прямая ссылка на изображение приведет к ошибке 403 «Требуется авторизация», поскольку браузер не будет отправлять заголовки аутентификации OAuth. Однако я установлю их в запросе JavaScript.   -  person JochenJung    schedule 01.07.2011


Ответы (7)


Йохен,

Я провел обширные тесты с различными библиотеками кодирования Base64:

Тестовый код:

public static void main(String [] args) throws IOException {
    File file = new File("./resources/so.png");
    BufferedInputStream bufRead =  new BufferedInputStream(new FileInputStream(file));
    ByteBuffer buffer = ByteBuffer.allocate(30*1024) ; // x kb
    byte[] c = new byte[1];     
    while ((bufRead.read(c))>0) { //1 byte/time to avoid buffer arithmetics 
        buffer.put(c);
    }
    byte[] data = new byte[buffer.position()];
    buffer.flip();
    buffer.get(data);
    String dataAsSt = new String(data); // transform the data to a string -- encoding error-prone
    //gwt-base64
    //String gwtBase64 = GwtBase64.encode(dataAsSt);  //doesn't work

    //google base64 impl
    String googleBase64 = Base64Utils.toBase64(data);

    //apache base64 codec
    Base64 base64codec = new Base64(-1);
    String apacheBase64 = base64codec.encodeToString(data);

    System.out.println("Google:"+googleBase64);
    System.out.println("Apache:"+apacheBase64);
    //System.out.println("GWTb64:"+gwtBase64);
}

Выводы:

  • (gwt-base64) вообще не работает. Это не удалось с: java.lang.StringIndexOutOfBoundsException: String index out of range на каждом изображении, которое я пробовал. Обратите внимание, что я закомментировал код.

  • (google) Создаваемая им кодировка Base64 не может быть понята браузером.

  • (apache) Работает с этим конструктором: new Base64(-1) = без структурных линий, без URL-безопасности.

Заслуга: вы можете заставить реализацию Google работать, если измените последние 2 символа карты символов: «$», «_» на «+», «/».

Мой главный вывод заключается в том, что библиотека Base64, которую вы сейчас используете, содержит ошибки. Я предлагаю при поиске альтернативных реализаций попытаться сохранить поток байтов между изображением и кодировщиком base64 в двоичном формате (byte[]). Строка может работать, если используется одно и то же кодирование/декодирование, но это рискованно, если кодирование и декодирование выполняются в двух разных местах (например, клиент/сервер).

Удачи!

P.S. Попробуйте этот :-)

<img src="data:unknown;base64,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"/>

Изменить: дополнительные исследования

Я потратил больше времени, чем разумно, пытаясь найти решение. Оболочка GWT не позволит вам получить необработанные данные, но вы можете использовать JSNI, чтобы заставить браузер получить двоичные данные:

native String getBinaryResource(String url) /*-{
    // ...implemented with JavaScript                 
    var req = new XMLHttpRequest();
    req.open("GET", url, false);  // The last parameter determines whether the request is asynchronous -> this case is sync.
    req.overrideMimeType('text/plain; charset=x-user-defined');
    req.send(null);
    if (req.status == 200) {                    
        return req.responseText;
    } else return null
}-*/;
  • Этот блог JS очень помог.
  • Этот ресурс отлично подходит для понимания работы Javascript: XMLHTTPRequestObject

Люблю раскалывать крепкий орешек, но я применил все это, и все же кодировка base64 не работает. Между JS и Java-оболочкой все еще существует проблема с кодировкой, и я не могу получить декодированную строку обратно в правильный байт []. Перепробовал все возможные комбинации кодировок. Возможный способ - использовать base64 для req.responseText с использованием собственной библиотеки javascript и вернуть строку java-аналогу.

Пока что по исходному вопросу.

Теперь рассмотрим некоторые альтернативные идеи и требования, лежащие в основе вашего вопроса: во время моего исследования я увидел, что Base64 очень часто используется для встроенных изображений на стороне сервера, чтобы избежать дополнительных HTTP-заголовков для получения изображения у клиента. Похоже, это популярная альтернатива встраиванию CSS.

В контексте этого вопроса код работает на клиенте (браузере), и эти причины не применяются. Использование базового XMLHTTPRequest для получения двоичного файла изображения создает дополнительный HTTP-запрос от вашего браузера к серверу. Учитывая, что в контексте клиента у вас, очевидно, есть URL-адрес изображения (передается в IoProvider.get().makeRequest(*url*,...), есть ли причина, по которой мы не можем позволить браузеру выполнить задание через простое динамическое обновление, если объект изображения:

(это может быть не лучший пример кода, но он дает вам представление (извините за каламбур ;-))

void setImage(String url) {
    final HTML imageHolder = new HTML();
    String imgTag = "<IMG src='"+url+"' />'";
    imageHolder.setHTML(imgTag);
    RootPanel.get("imageContainer").add(imageHolder); // imageContainer is a div
}

Правка: орех треснул

Наконец-то нашел последнюю недостающую часть головоломки: как правильно декодировать двоичные данные из строки JavaScript. Обратите внимание на некоторые предостережения: не будет работать в IE, поскольку они не поддерживают метод overrideMimeType для собственного XMLHTTPRequest.

native String getBinaryResource(String url) /*-{
    var req = new XMLHttpRequest();
    req.open("GET", url, false);  // The last parameter determines whether the request is asynchronous.
    req.overrideMimeType('text/plain; charset=x-user-defined');

    req.send(null);
    if (req.status == 200) {
        return req.responseText;
    } else return null
}-*/;

private void sendRequestBinary() {
    String url = URL.encode("/Computer_File_030.gif");
    String data = getBinaryResource(url);
    if (data != null) {
        // The secret sauce: Method to decode the binary data in the response string
        byte[] binData = new byte[data.length()];
        for (int i=0;i<data.length();i++) {
            binData[i] = (byte)(data.charAt(i) & 0xff);
        }
        final HTML imageHolder = new HTML();
        String base64=Base64Utils.toBase64(binData);

        String imgTag = "<IMG src='data:image/gif;base64,"+base64+"' />'";
        imageHolder.setHTML(imgTag);
            RootPanel.get("imageContainer").add(imageHolder);
            errorLabel.setText("Base64:");
    } else {
        errorLabel.setText("Another error :-(");
    }
}
person maasg    schedule 27.06.2011
comment
Спасибо за ваше исследование. Но я не могу заставить ни Base64Utils, ни apacheBase64 работать с GWT на стороне клиента. [ОШИБКА] Строка 317: исходный код недоступен для типа com.google.gwt.user.server.Base64Utils; вы забыли наследовать необходимый модуль? - И если я включу его в свой файл .gwt.xml, он тоже не будет работать. В этом ответе говорится, что его можно использовать только на стороне сервера. ="попытаться использовать base64utils, но компилятор gwt не работает"> stackoverflow.com/questions/4740865/ - person JochenJung; 28.06.2011
comment
@JochenJung код google impl из Base64 кажется мне довольно чистым, чтобы его можно было перевести компилятором GWT js. Не могли бы вы просто добавить код src в свою сборку? Давненько я не делал GWT. Я думаю, это должно быть возможно. - person maasg; 28.06.2011
comment
Хорошая идея. Теперь я могу использовать Base64Utils.toBase64() и переписал $ и _ на + и /. Однако изображение по-прежнему не отображается. Я отредактировал свой вопрос и поместил туда новый вывод. Я также попытался изменить кодировку. Я думаю, что кодировщик Base64 в порядке, так как вы уже проверили его. Проблема заключается в том, что я не могу получить доступ к байту [], как в исходном изображении. Так как response.getText() может уничтожить его. - person JochenJung; 28.06.2011
comment
@JochenJung Я расколол орех! Подробности выложу позже! - person maasg; 01.07.2011
comment
Вы нашли решение? Что касается вашего последнего редактирования: невозможно просто обменять src изображения, поскольку изображение вернет 403 Требуется авторизация, поскольку HTTP-заголовки OAuth не были отправлены. Чтобы иметь доступ к файлу, необходимо отправить эти заголовки. GWT генерирует их для меня, поэтому я застрял с получением изображения через сгенерированный GWT JavaScript, а затем пытаюсь отправить его в браузер. Задержка для меня не проблема. Если бы JS мог сохранить изображение где-нибудь, где браузер может получить к нему доступ, меня бы это устроило. Но afaik JS не может хранить файлы, поэтому мне придется использовать встроенные изображения. - person JochenJung; 01.07.2011
comment
@JochenJung После прочтения этого: вот почему я застрял с получением изображения через сгенерированный GWT JavaScript, у вас может не быть полного решения. Я не нашел решения на основе GWT для получения двоичного потока. Только JSNI справится с задачей, но тогда у вас есть заголовки OAuth... возможно, вы можете поиграть между JSNI и GWT, чтобы получить лучшее из обоих миров. - person maasg; 01.07.2011
comment
Попробую в понедельник. Возможно, я мог бы расширить JS, чтобы он отправлял информацию OAuth. Спасибо за все ваши усилия! Мне очень помог! - person JochenJung; 01.07.2011
comment
Нет проблем. Многому научился в процессе. - person maasg; 01.07.2011
comment
этот ответ только что спас мою задницу, порт кодировщика Base64 с GWT не работает, и я трачу почти четыре часа, используемый кодек от apache ... и работает как по волшебству, я думаю, что есть проблема с RFC - person Forhad; 16.04.2013

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

http://en.wikipedia.org/wiki/Data_URI_scheme

данные:[][;charset=][;base64],

person mP.    schedule 20.06.2011
comment
Вы имеете в виду параметр charset=? Я пробовал data:unknown;charset=utf-8;base64, и это не сработало. - person JochenJung; 20.06.2011

Вы уверены, что данные изображения, которые вы получили, верны? Поскольку вы запрашиваете изображение в виде текста, возможно, GWT обрабатывает двоичные данные перед вызовом вашего обратного вызова (например, экранирование непечатаемых символов).

person Jcs    schedule 24.06.2011
comment
Да, я создал ‹img... с помощью GWT. Я поместил его внутрь callback.onSuccess(data:unknown;base64,workingbase64imagecode); - person JochenJung; 24.06.2011

unknown не является допустимым типом MIME. Ваш URI данных должен начинаться с data:image/png или любого другого значения, подходящего для отображаемого изображения. Несмотря на неверный тип MIME, утилита file не распознает декодированные данные из первого отправленного вами URL-адреса. Что это должен быть за файл?

person BobV    schedule 25.06.2011
comment
Хотя это недопустимый MIME-тип, большинство браузеров достаточно умны, чтобы смотреть на файловые маркеры и определять MIME-тип, поэтому, скорее всего, кодировка неверна. - person ClassicThunder; 25.06.2011
comment
Я устал изображения/jpg изображения/png и изображения/gif. Ни один из них не работал. Я не думаю, что это нужно, так как работа изображения также неизвестна. - person JochenJung; 27.06.2011

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

В любом случае есть 2 места, где я вижу, что что-то идет не так.

1) Ваш response.getText() не является правильной кодировкой изображения. Только проблема, если вы загружаете из БД или используете инструмент, который генерирует изображение как экземпляр класса Java Image.

2) Вы должны установить тип пантомимы. data:unknown должен быть допустимым типом mimetype, например data:image/jpeg (ссылка http://www.w3schools.com/media/media_mimeref.asp) Если вы не установите MIME-тип, браузер должен угадать, и если он угадает неправильно, ваше изображение не будет отображаться.

Я предлагаю использовать установленный кодек с соответствующим типом mime (jpeg, gif, png), предполагая, что вы загружаете из byte[], а не из файла, и я также предлагаю использовать sun.misc.BASE64Encoder().encode(byte[]) так как вы можете быть уверены, что он работает как задумано.

Сторона клиента

ThecoderslibraryGWT.loginService.capImage( 
        new AsyncCallback<String>() {

    @Override
    public void onFailure(Throwable caught) {
        error.setHTML(caught.getMessage());
    }

    @Override
    public void onSuccess(String result) {
        String base64EncodedImage = result;             
        img.setUrl("data:image/jpg;base64," + base64EncodedImage);
        vp.setVisible(true);
    }
});


Сторона сервера

/**
 * 64 Bit encoded captcha image
 */
public String capImage() {

    byte[] data = null;

    // the output stream to render the captcha image as jpeg 
    ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
    try {                       
        // get the session id that will identify the generated captcha. 
        //the same id must be used to validate the response, the session id is a good candidate!
        String captchaId = this.getThreadLocalRequest().getSession().getId();

        BufferedImage challenge = CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId, this.getThreadLocalRequest().getLocale());

        // a jpeg encoder
        JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);

        jpegEncoder.encode(challenge);


        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(challenge, "jpg", os);
        data= os.toByteArray();         

    } catch (IllegalArgumentException e) {
        e.printStackTrace();
        throw new IllegalArgumentException("Unable to create validation image.");
    } catch (CaptchaServiceException e) {
        e.printStackTrace();
        throw new IllegalArgumentException("Unable to create validation image.");
    } catch (IOException e) {
        e.printStackTrace();
        throw new IllegalArgumentException("Unable to create validation image.");
    }

    return new sun.misc.BASE64Encoder().encode(data);
}
person ClassicThunder    schedule 25.06.2011
comment
Я забыл упомянуть, что мой код предназначен только для клиентской части. На стороне сервера находятся контакты Google. Я достаю картинку оттуда. Я прочитал это с помощью сгенерированного GWT javascript. Я не могу напрямую связать URL-адрес изображения, поскольку это может привести к необходимости аутентификации 403. JavaScript отправляет заголовки OAuth при запросе файла, который возвращает мне данные изображения. Поскольку Javascript не может записывать файлы, мне нужно передать код изображения как встроенное изображение. - person JochenJung; 27.06.2011
comment
sun.misc.BASE64Encoder работает только на стороне сервера. Использование image/jpeg не помогло. Я предполагаю, что проблема связана с преобразованием String или кодировкой Base64. Но я уже пробовал два разных класса Base64encoding. - person JochenJung; 27.06.2011

2 вероятные причины:

1) Ваш код на стороне сервера, читающий изображение и отправляющий его через HTTP, искажает кодировку двоичного формата изображения перед входом в Base64.encode(response.getText()). Если у вас есть доступ к серверу, Base64.encode ваше изображение на сервере и просто передать его через:

callback.onSuccess("data:unknown;base64,"+ response.getText()); // response already in Base64

2) Если у вас нет доступа к серверной части, попробуйте избежать перевода строки в вызове response.getText().

new ResponseReceivedHandler<byte[]>() {
    public void onResponseReceived(ResponseReceivedEvent<byte[]> event) {
        final Response<byte[]> response = event.getResponse();
            if (response.getStatusCode() == HTTP_OK){
                callback.onSuccess("data:unknown;base64," + Base64.encode(**response.getData()**));
            }
        }
     }, options);
} catch ...
person maasg    schedule 26.06.2011
comment
К сожалению, у меня нет доступа к серверу. Это изображение контактов Google, я пытаюсь получить доступ. Чтобы запросить URL-адрес, содержащий изображение, мне нужно отправить заголовки OAuth (что работает). Поскольку мой код работает только на стороне клиента, мне нужно использовать встроенные изображения (JavaScript не может хранить файлы). - person JochenJung; 27.06.2011
comment
Как я могу избежать перевода строки? Afaik есть только IoProvider.get().makeRequestAsText() и нет IoProvider.get().makeRequestAsByte - person JochenJung; 27.06.2011
comment
@JochenJung вы пробовали: public void makeRequest (окончательный URL-адрес строки, окончательный обработчик ResponseReceivedHandler‹Object›); После этого проверьте тип объекта из Response‹Object› response = event.getResponse(); У меня сложилось сильное впечатление, что это внутренний процесс кодирования преобразования потока изображения в строку в методе getText(), который возится с содержимым. - person maasg; 27.06.2011
comment
в javadoc для метода makeRequestAsText(...) говорится: Этот метод можно использовать для получения любых текстовых данных. - person maasg; 27.06.2011
comment
Ваш выбор impl для кодировки Base64 также является потенциальным подозреваемым. Он принимает строку в качестве входных данных, тогда как он должен принимать byte[], чтобы избежать предположений о кодировке символов. Я нашел эту серверную версию. Вы также можете включить его на стороне клиента: goo.gl/yhM8u - person maasg; 27.06.2011
comment
makeRequest() также не принимает byte[]. Единственными альтернативами являются makeRequestAsDOM и makeRequestAsJSO. Думаю, мне придется реализовать аналогичный makeRequestAsByte(). Я надеялся использовать существующие, поскольку запросы из гаджетов Gmail, где запущено мое приложение, немного сложны. - person JochenJung; 27.06.2011
comment
Я уже пробовал Base64Utils, на которые вы ссылались, но они работают только на стороне сервера. Но я также думаю, что получение содержимого URL-адресов в виде byte[] вместо String — это первая проблема, которую мне нужно исправить. Хотя я пока не знаю, как написать makeRequestAsByte. - person JochenJung; 27.06.2011
comment
@JochenJung Я провожу тесты с библиотеками Base64. Подождите немного. Поделюсь дополнительной информацией. - person maasg; 27.06.2011
comment
Я снова попробовал makeRequest(), и он работает, хотя мне все еще нужно преобразовать его в String (см. Раздел EDIT в моем вопросе). Любые идеи, как получить ответ, не преобразовывая его в строку? - person JochenJung; 27.06.2011

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

//Клиент

public void onModuleLoad() {
    HTML html = new HTML(
            "<img src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0 vr4MkhoXe0rZigAAAABJRU5ErkJggg==\" alt=\"Red dot\">");

    RootPanel.get().add(html);

    greetingService.greetServer("", new AsyncCallback<String>() {

        @Override
        public void onSuccess(String result) {
            HTML html = new HTML(
                    "<img src=\"data:image/png;base64, "+ result + "\" alt=\"Window Logo\">");

            RootPanel.get().add(html);
            RootPanel.get().add(new Label(result));

        }

        @Override
        public void onFailure(Throwable caught) {
            // TODO Auto-generated method stub

        }
    });
}

// сервер

общедоступная строка welcomeServer (ввод строки) выдает исключение IllegalArgumentException {

    // BASE64Encoder

    try{FileInputStream img = new FileInputStream(
            "C:\\icon_a.png");
    ByteArrayBuffer bab = new ByteArrayBuffer(0);
    int eof = 0;
    while (eof != -1) {
        eof = img.read();
        bab.append(eof);
    }

     String rets = new BASE64Encoder().encode(bab.toByteArray());
        return rets;

    }catch (Exception e) {
        // TODO: handle exception
    }

    return null;
}

PS: это изображение http://www.drweb.de/icons/twitter/pd_twitter_iconset/pd_twitter_iconset/PNG/256/icon_a.png

person Stefan    schedule 01.07.2011