2013-02-27 1 views
7

У меня есть решение для копирования текстового содержимого из одного документа в MIME в другом документе. См. http://per.lausten.dk/blog/2012/12/xpages-dynamically-updating-rich-text-content-in-a-ckeditor.html. Я использую это в приложении как способ для пользователя вставлять шаблоны контента в новый документ и показывать контент в режиме «на лету» в CKEditor.Копирование богатого текста и изображений из одного документа в MIME в другом документе

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

Как включить изображения?

Обновление от 4 октября 2013 года: Я все еще ищу решение для этого.

+1

Требуется некоторая магизация MIME. Я пытаюсь что-то приготовить для тебя. – stwissel

ответ

4

Я, наконец, получил его работу. Это было намного проще и даже не включало MIME. Хитрость в том, чтобы изменить тег изображений в рабочем HTML включить в формате base64 изображения таким образом, что SRC тег может использовать этот формат (здесь показан с GIF, как пример):

src="data:image/gif;base64,<base64 encoded image>" 

я уже имел необходимый код чтобы получить HTML из поля с большим текстом (см. my blog post, уже упомянутый в моем вопросе). Поэтому мне нужно было заменить теги src изображения на правильный формат src, включая кодированное изображение base64.

Следующий код получает HTML и проходит через каждый из включенных изображений и изменяет Src тег:

String html = this.document.getValue(fieldName).toString(); 
if (null != html) { 
    final List<FileRowData> fileRowDataList = document.getEmbeddedImagesList(fieldName); 
    if (null != fileRowDataList) { 
     final Matcher matcher = imgRegExp.matcher(html); 
     while (matcher.find()) { 
      String src = matcher.group(); 
      final String srcToken = "src=\""; 
      final int x = src.indexOf(srcToken); 
      final int y = src.indexOf("\"", x + srcToken.length()); 
      final String srcText = src.substring(x + srcToken.length(), y); 
      for (FileRowData fileRowData : fileRowDataList) { 
       final String srcImage = fileRowData.getHref(); 
       final String cidImage = ((AttachmentValueHolder) fileRowData).getCID(); 
       final String typeImage = ((AttachmentValueHolder) fileRowData).getType(); 
       final String persistentName = ((AttachmentValueHolder) fileRowData).getPersistentName(); 

       // Add base 64 image inline (src="data:image/gif;base64,<name>") 
       if (srcText.endsWith(srcImage)) { 
        final String newSrc = src.replace(srcText, "data:" + typeImage + ";base64," + getBase64(persistentName)); 
        html = html.replace(src, newSrc); 
       } 
      } 
     } 
    } 
} 

Вот метод getBase64(), который base64 кодирует изображение:

private String getBase64(final String fileName) { 
    String returnText = ""; 
    try { 
     BASE64Encoder base64Enc = new BASE64Encoder(); 
     ByteArrayOutputStream output = new ByteArrayOutputStream(); 
     base64Enc.encode(this.getEmbeddedImageStream(fileName), output); 
     returnText = output.toString(); 
    } catch (NotesException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return returnText; 
} 

Некоторые из кода взяты из emailBean by Tony McGuckin.

+0

Прохладный действительно. Мое использование встроенных изображений вдохновило вас? Что было бы интересно сравнить с регулярным выражением с эффективностью анализатора и/или ремонтопригодностью Jericho – stwissel

2

Вы можете получить дескриптор встроенного изображения по DominoDocument.AttachmentValueHolder см http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/XPagesExtAPI/8.5.2/com/ibm/xsp/model/domino/wrapped/DominoDocument.AttachmentValueHolder.html

Я писал о вложениях внутри примечаний документов см http://www.domino-weblog.nl/weblogs/Domino_Blog.nsf/dx/xpages-tip-get-easily-access-to-your-attachments-in-java.htm

+1

Я только что открыл метод getBodyHTML в emailBean Тони МакГакеном по адресу http://openntf.org/XSnippets.nsf/snippet.xsp?id=emailbean-send-dominodocument-html-emails-cw-embedded-images-attachments- заказ HeaderFooter. Это выглядит интересно. Он также использует AttachmentValueHolder –

1

Gruesome хак (вам нужно разобраться в подлинности и сервер имена)

SSJS (получение источника с целью)

var unid = curRow.getUniversalID(); 
var body = getComponent("body1"); 
var magic = new demo.HTMLMagic(); 
magic.doMagic(database, unid, body); 

Java

package demo; 


import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.util.List; 
import org.apache.http.HttpHost; 
import org.apache.http.HttpResponse; 
import org.apache.http.HttpVersion; 
import org.apache.http.client.ClientProtocolException; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.conn.ClientConnectionManager; 
import org.apache.http.conn.scheme.PlainSocketFactory; 
import org.apache.http.conn.scheme.Scheme; 
import org.apache.http.conn.scheme.SchemeRegistry; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; 
import org.apache.http.params.BasicHttpParams; 
import org.apache.http.params.HttpParams; 
import org.apache.http.params.HttpProtocolParams; 

import net.htmlparser.jericho.Attribute; 
import net.htmlparser.jericho.Attributes; 
import net.htmlparser.jericho.HTMLElementName; 
import net.htmlparser.jericho.OutputDocument; 
import net.htmlparser.jericho.Source; 
import net.htmlparser.jericho.StartTag; 
import lotus.domino.Database; 
import lotus.domino.NotesException; 

import com.ibm.misc.BASE64Encoder; 
import com.ibm.xsp.component.xp.XspInputRichText; 
import com.ibm.xsp.http.IMimeMultipart; 
import com.ibm.xsp.model.domino.wrapped.DominoRichTextItem; 

public class HTMLMagic { 

private HttpClient   httpClient = null; 
private HttpHost   httpHost = null; 
//TODO: that needs to be resolved smarter 
private static final String HOSTNAME = "localhost"; 

public void doMagic(final Database database, final String unid, final XspInputRichText body) throws NotesException, 
     ClientProtocolException, IOException { 
    final String docURL = "http://" + HOSTNAME + "/__" + database.getReplicaID() + ".nsf/0/" + unid + "/Body?OpenField"; 
    final String fixedHTML = this.fixHTML(docURL); 
    IMimeMultipart result = DominoRichTextItem.convertToMime("-- copied text--<br />" + fixedHTML); 
    body.setValue(result); 
} 

private String fixHTML(final String rawHTMLstring) throws ClientProtocolException, IOException { 
    HttpHost target = this.getHttpHost(); 
    HttpClient client = this.getHttpClient(); 
    HttpGet get = new HttpGet(rawHTMLstring); 
    HttpResponse response = client.execute(target, get); 
    InputStream data = response.getEntity().getContent(); 
    Source rawHTML = new Source(data); 
    OutputDocument outputDocument = new OutputDocument(rawHTML); 
    StringBuilder sb = new StringBuilder(); 
    String tagName = HTMLElementName.IMG; 
    String attName = "src"; 
    List<StartTag> links = rawHTML.getAllStartTags(tagName); 

    for (StartTag onelink : links) { 
     String href = onelink.getAttributeValue(attName); 
     if (href != null) { 
      String replace = this.urltoData(href); 
      if (replace != null) { 
       sb.setLength(0); 
       sb.append("<"); 
       sb.append(tagName); 
       sb.append(" "); 
       sb.append(attName); 
       sb.append("=\""); 
       sb.append(replace); 
       sb.append("\""); 
       Attributes atts = onelink.getAttributes(); 
       if (!atts.isEmpty()) { 
        for (int i = 0; i < atts.size(); i++) { 
         Attribute att = atts.get(i); 
         if (!att.getName().equals(attName)) { 
          sb.append(" "); 
          sb.append(att.getName()); 
          sb.append("=\""); 
          sb.append(att.getValue()); 
          sb.append("\" "); 
         } 
        } 
       } 
       sb.append(">"); 
       outputDocument.replace(onelink, sb.toString()); 
      } 
     } 
    } 
    return outputDocument.toString(); 
} 

private HttpClient getHttpClient() { 

    if (this.httpClient == null) { 

     // general setup 
     SchemeRegistry supportedSchemes = new SchemeRegistry(); 

     // Register the "http" protocol scheme, it is required 
     // by the default operator to look up socket factories. 
     supportedSchemes.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 

     // prepare parameters 
     HttpParams params = new BasicHttpParams(); 
     HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
     HttpProtocolParams.setContentCharset(params, "UTF-8"); 
     HttpProtocolParams.setUseExpectContinue(params, true); 

     ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, supportedSchemes); 
     this.httpClient = new DefaultHttpClient(connMgr, params); 
    } 
    return this.httpClient; 
} 

private HttpHost getHttpHost() { 
    if (this.httpHost == null) { 

     this.httpHost = new HttpHost(HOSTNAME, 80, "http"); 
    } 
    return this.httpHost; 
} 

private String urltoData(final String href) throws ClientProtocolException, IOException { 
    StringBuilder sb = new StringBuilder(); 
    sb.append("data:image/"); 
    sb.append(href.substring(href.lastIndexOf("FieldElemFormat=") + 1)); 
    sb.append(";base64,"); 

    // Here go the Image data 
    HttpHost target = this.getHttpHost(); 
    HttpClient client = this.getHttpClient(); 
    HttpGet get = new HttpGet(href); 
    HttpResponse response = client.execute(target, get); 
    InputStream data = response.getEntity().getContent(); 

    BASE64Encoder encoder = new BASE64Encoder(); 
    OutputStream output = new ByteArrayOutputStream(); 
    encoder.encode(data, output); 
    sb.append(output.toString()); 
    output.close(); 

    return sb.toString(); 
} 

} 

Было бы интересно, если это сработает для вас. Клиент Notes не может отображать встроенные HTML-изображения

+0

Конечно: вместо того, чтобы сжать данные изображения полностью в линию, вы можете превратить их в правильные части MIME. В общем тот же подход. Вы также можете вытащить DXL вместо использования HTTP, чтобы перейти к версии образа Base64. – stwissel

+0

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

+0

Да. Вам нужно сгенерировать токен из сеанса HTTP. Alternsate: DXL поставляет изображения, закодированные слишком – stwissel