2010-10-24 49 views
1

我有一些NotesDocument,其中某些RichText字段同時具有文本和內嵌圖像。我可以獲取該文本的文本部分,但無法使用lotusscript檢索內嵌圖像。任何人都可以建議我從這些文檔中檢索內嵌圖像。 LotusScript代碼:使用lotusscript檢索蓮花筆記的內嵌圖像

Sub Click(Source As Button) 
    Dim session As New NotesSession 
    Dim db As NotesDatabase 
    Dim mainDoc As NotesDocument 
    Dim v As NotesView 
    Set db = session.CurrentDatabase 

    Dim fileName As String 
    Dim fileNum As Integer 
    fileNum% = Freefile() 
    fileName$ = "D:\data.txt" 
    Open FileName$ For Append As fileNum% 

    Set v = db.GetView("MyView") 
    Set mainDoc = v.GetFirstDocument  

    While Not (mainDoc Is Nothing)    
     Forall i In mainDoc.Items 
      If i.Type = RICHTEXT Then 
       Write #fileNum% , i.Name & ":" & i.text 'how the images?? 
      End If 
     End Forall    
     Set mainDoc = v.GetNextDocument(mainDoc) 
    Wend 
End Sub 

謝謝。

回答

0

我建議你看看Genii Software MidasLSX產品。它們提供了LotusScript擴展包,可以更輕鬆地處理Lotus Notes Rich Text項目的複雜性。

http://www.geniisoft.com/showcase.nsf/MidasHelp

否則,您可以用NotesRichTextNavigator類實驗獲得的富文本項目獲取圖像(理論上)。關於這類事情的文檔很少。我無法完全知道圖像會如何使用該類,但假設您瀏覽豐富的文本項並能夠將圖像作爲NotesEmbeddedObject進行處理,我知道有一種方法可以將對象保存到磁盤上那個班。

另一個(瘋狂的)想法是通過電子郵件發送文檔,並讓其他程序能夠更輕鬆地處理郵件正文。 Notes對處理自己的富文本字段沒有多大幫助。

2

邁達斯是最簡單的方法,但它不是免費的。 (在整個時間內節省的錢都是值得的,但是如果你的組織與我工作的組織相似,那麼這個工具的全部成本將會在擁有當前項目的計費單元上得到強化,而而不是在整個組織中分攤),並且在同意成本之前它們可能會改變它們的需求。)還有另一種方法,那就是使用導出選項ConvertNotesBitmapToGIF將數據庫導出到DXL(Domino XML)。圖像將以XML格式顯示爲<picture>元素與Base64編碼的數據。如果您完全在Notes環境中操作,則需要創建一個臨時文檔,其中包含用作NotesMIMEEntity的富文本字段,以將編碼後的圖片轉換爲二進制文件,然後將其傳輸到文件(使用NotesStream)。所有這些都假定您正在使用版本6或更高版本;如果你使用R5或更早的版本,Midas或使用C API直接訪問CD記錄是唯一可行的方法。

-1

這是我用來從文檔上的richtext字段中分離文件的代理。

Option Public 
Dim uidoc As notesuidocument 
Dim doc As NotesDocument 
Dim db As NotesDatabase 
Dim obj As NotesEmbeddedObject 
Dim collection As NotesDocumentCollection 
Dim rt As Variant 
Dim attachNames As Variant 
Dim i As Integer, x As Integer 
Dim j As Integer 
' Agent - Detach Attachments to C drive for later reattachment 
' Copies all attachment in richtext field to personal directory. 

Sub Initialize 
    Dim ws As New notesuiworkspace 
    Dim ses As New NotesSession 
    Set db = ses.CurrentDatabase 
    Set collection = db.UnprocessedDocuments 
    ' get first doc in collection 
    For j = 1 To collection.Count 
     Set doc = collection.GetNthDocument(j)  
' --- create array of filenames of all the attachments in the document 
     i = 0 
     Redim attachNames(i) 
     Forall x In doc.items 
      If x.name = "$FILE" Then 
       attachNames(i) = x.values(0) 
       i = i + 1 
       Redim Preserve attachNames(i) 
      End If 
     End Forall 

     If i > 0 Then 
      Redim Preserve attachNames(i-1) 
     End If 

' --- for all of the filenames in attachNames, if it exists in the rich text field, detatch them 
     If doc.hasItem("richtextfieldname") Then 
      Set rt = doc.GetFirstItem("richtextfieldname") 
     End If 
     If attachNames(0) <> "" Then 
      Forall x In attachNames 
       Set obj = rt.GetEmbeddedObject(x) 
       If Not(obj Is Nothing) Then 
        Call obj.ExtractFile("C:\path\" & Cstr(x)) 
       End If 
      End Forall 
     End If 
     Call doc.save(True, False) 
    Next 
End Sub 
0

七年後,我一直拉着這頭髮。 Rod H的答案是附件,但嵌入圖像完全是另一回事。

我的最佳運氣來自位於這裏的@ andre-guirard的LotusScript Gold Collection代碼:https://www.openntf.org/main.nsf/project.xsp?r=project/LotusScript%20Gold%20Collection然而,這並沒有得到所有的東西,因爲它不能處理嵌入圖像以舊方式嵌入的文檔。 (注改變它存儲嵌入圖像的方式。)

我很努力把它與這裏介紹AGECOM的信息相結合:通過改變安德烈的EmbeddedImage對象通過尋找內的富人們如果嵌入圖像無縫地處理這兩種格式https://www.agecom.com.au/support/agecomkb.nsf/0/58cbf10f0ab723c9ca25803e006c7de8?OpenDocument文本字段實際上只是一個指向$ FILE字段的指針,如果有的話,獲得一個FileItem對象,但最終我將我的理解和選項用盡了,我無法證明我的僱主的資源(我的時間)花在了它上面。

因此,如果你有新的方式包含嵌入的圖像,我認爲安德烈的代碼將工作不受干擾。否則,我盡我所能,但我沒有一個答案 ...我有什麼是(對我來說)一個死衚衕,提出的希望,你或其他人誰絆倒可以通過解釋什麼使我難堪我做錯了!

基本上,我開始與安德烈的代碼,並改變了它在以下方面...

在DOMUtils,添加下面的方法:

%REM 
    Function DU_GetMeOrNextSiblingWithAttr 
    Description: Starting with a particular node, return that node or the next sibling with an attribute that has a particular value. 
     Does not recurse into the tree; looks only at the node passed and later siblings. 
    Parameters: 
     nodeStart: node to start your search with. 
     targetElement: element name of desired node. 
     attrName: attribute name you want to check. 
     attrValue: attribute value of element you're looking for. 
     flags: string-matching flags to compare attribute, e.g. 1 for case insensitive. 
%END REM 
Function DU_GetMeOrNextSiblingWithAttr(nodeStart As NotesDOMNode, ByVal targetElement$, ByVal attrName$, ByVal attrValue$, ByVal flags%) As NotesDOMElementNode 
    Dim node As NotesDOMNode, elTmp As NotesDOMElementNode 
    Set node = nodeStart 
    Do Until node.Isnull 
     If node.Nodetype = DOMNODETYPE_ELEMENT_NODE Then 
      If node.Nodename = targetElement Then 
       Set elTmp = node 
       If StrComp(elTmp.Getattribute(attrName), attrValue, flags) = 0 Then 
        Set DU_GetMeOrNextSiblingWithAttr = elTmp 
        Exit Function 
       End If 
      End If 
     End If 
     Set node = node.Nextsibling 
    Loop 
End Function 

更換FileItem.New用下面的代碼:

%REM 
    Sub New 
    Description: Arguments are the parsed DOM node of the element representing a 
     design element, and the name of the composite item you would like to read, 
     modify or create. 
%END REM 
Sub New(parent As FileItemParent, elNote As NotesDOMElementNode, itemName$, fileName$) 
    Set m_elNote = elNote 

    SetItem elNote, itemName$, fileName$ 


    Dim node As NotesDOMNode 
    Set node = m_elNote.Parentnode 
    While node.Nodetype <> DOMNODETYPE_DOCUMENT_NODE 
     Set node = node.Parentnode 
    Wend 
    Set m_domd = node 
    parent.RegisterFileItem Me ' make sure the design element knows about us. 
     ' (in case someone gets smart and invokes the constructor directly 
     ' instead of using the nice methods we've provided). 
End Sub 

%REM 
    Sub SetItem 
<!-- Created Dec 6, 2017 by JSmart523 --> 
    If fileName$ is blank, returns the XPath equivalent of elNote/ancestor::document/item[@name=itemName$][position()=1] 
    If fileName$ is not blank, returns the XPath equivalent of elNote/ancestor::document/item[@name=itemName$][object/file/@name=fileName$][position()=1] 

    Case insensitive. Changes itemName$ and fileName$ to the correct case if found. 

    Also sets Me.m_elItem to the returned NotesDOMElementNode 
    Also sets Me.m_elRawData to the file contents 
%END REM 
Sub SetItem(elNote As NotesDOMElementNode, itemName$, fileName$) 
    Dim elFile As NotesDOMElementNode 
    Dim node As NotesDOMNode 

    'set node to ancestor::document 
    Set node = elNote 
    Do Until node.NodeName = "document" 
     Set node = node.ParentNode 
    Loop 

    'If fileName$ = "", get the first ancestor::document/item[@name=itemName$] 
    'Otherwise,   get the first ancestor::document/item[@name=itemName$][/object/file/@name=fileName$] 
    Set m_elItem = DU_GetChildOfType(node, DOMNODETYPE_ELEMENT_NODE) 
    QualifyingItem m_elItem, itemName$, m_elRawData, fileName$ 
    m_itemName = itemName$ 
    m_fileName = fileName$ 
End Sub 

%REM 
    Sub QualifyingItem 
<!-- Created Dec 8, 2017 by JSmart523 --> 
    Starting with incoming elItem node, ensures it's an item we want or changes elItem to the first sibling that qualifies. 
%END REM 
Sub QualifyingItem(elItem As NotesDOMElementNode, itemName$, elRawData As NotesDOMElementNode, fileName$) 
    Dim elFile As NotesDOMElementNode 
    Dim node As NotesDOMNode 
    Dim elObject As NotesDOMElementNode 

    If Not elItem Is Nothing Then 
     'Initially, elItem is just a starting point, not necessarily the item we want. 
     'If it's an item with the right name, great, otherwise change elItem to the next sibling item with the right name. 
     Set elItem = DU_GetMeOrNextSiblingWithAttr(elItem, "item", "name", itemName$, 1) 

     If Not elItem Is Nothing Then 
      If fileName$ = "" Then 
       'we have the right item, and aren't looking for a file node, which means we want the rawitemdata node 
       Set elRawData = DU_getChildNamed("rawitemdata", elItem) 
      Else 
       'We are looking for a $FILE item that contains a file. 
       'There are possibly several $FILE items within a document, one for each file. We've got the right one if ./object/file/@name = fileName$ 
       Do 
        Set elObject = DU_GetChildNamed("object", elItem) 
        If Not elObject Is Nothing Then 
         Set elFile = DU_GetChildWithAttr(elObject, "file", "name", fileName$, 1) 
         If Not elFile Is Nothing Then 
          'Yay! We have the right elItem node! 
          Set elRawData = DU_GetChildNamed("filedata", elFile) 
          fileName$ = elFile.GetAttribute("name") 
          Exit Do 
         End If 
        End If 
        Set elItem = DU_GetMeOrNextSiblingWithAttr(elItem.NextSibling, "item", "name", itemName$, 1) 
       Loop Until elItem Is Nothing 
       'At this point, either we jumped out of the loop with a valid elItem and elRawData, or elItem is Nothing 
      End If 
     End If 
    End If 

    If elItem Is Nothing Then 
     'we didn't find the correct item 
     'make sure elRawData is changed to Nothing, too. 
     Set elRawData = Nothing 
    Else 
     itemName$ = elItem.GetAttribute("name") 
    End If 
End Sub 

另外在的FileItem腳本庫,添加一個新類,FileItemParent

%REM 
    Class FileItemParent 
<!-- Created Dec 5, 2017 by JSmart523 --> 
    This is a base class for objects that use FileItem objects 
%END REM 
Class FileItemParent 
    m_elElRoot As NotesDOMElementNode 
    m_elFD As NotesDOMElementNode 
    Public m_fileItem As FileItem 
    m_fItems List As FileItem ' list of FileItems we've created and returned to caller. 
    m_iMode As Integer 

    %REM 
     Property Get DOMElement 
     Description: Return the element node representing the design element. 
    %END REM 
    Public Property Get DOMElement As NotesDOMElementNode 
     Set DOMElement = m_elElRoot 
    End Property 

    %REM 
     Sub New 
     Arguments: 
      db: the database containing the design element. 
      elElement: the DOM element corresponding to the design note (e.g. the <note> 
       element). 
      domp: The DOM parser object containing elElement. 
    %END REM 
    Sub New(elElement As NotesDOMElementNode) 
     Set m_elElRoot = elElement 
    End Sub 

    Sub Delete 
     On Error Resume Next 
     ForAll thing In m_fItems 
      Delete thing 
     End ForAll 
    End Sub 

    %REM 
     Function HasItem 
     Description: Determine whether there's an item element in the note DXL with a 
      given item name. 
      Note that the presence of an item doesn't guarantee it's formatted as a file 
      CD record. 
    %END REM 
    Function HasItem(ByVal itemName$) As Boolean 
     HasItem = Not (DU_GetChildWithAttr(m_elElRoot, "item", "name", itemName, 1) Is Nothing) 
    End Function 


    %REM 
     Function RegisterFileItem 
     Description: For internal use -- lets the FileItem class notify us that it's 
      referencing our DOM tree so that we can delete the object if we erase the 
      corresponding item element. 
    %END REM 
    Sub RegisterFileItem(x As FileItem) 
     Set m_fItems(LCase(x.itemName)) = x 
     If m_FileItem Is Nothing Then 
      Set m_FileItem = x 
     End If 
    End Sub 

    %REM 
     Function GetFileItem 
     Description: Retrieve the FileItem object associated with a CD-record item. 
      An object will be returned even if the item doesn't exist, which you can 
      use to create the item via UpdateFile method. 
    %END REM 
    Function GetFileItem(itemName$, fileName$) As FileItem 
     Set GetFileItem = New FileItem(Me, m_elElRoot, itemName, fileName) 
    End Function 

End Class 

FileItemParent類主要是取自Andre的FileResource類的代碼,以便FileResource和EmbeddedImage都可以使用它。更改FileResource以擴展FileItemParent,刪除任何重複的代碼。

現在我們要更改EmbeddedImage,以便即使嵌入式圖像節點包含指向$ FILE項目的鏈接而不是實際內容,也請返回實際內容。

因此,改變EmbeddedImage延長FileItemParent

添加/替換下面的方法來EmbededImage

%REM 
    Sub InitFileItem 
<!-- Created Dec 6, 2017 by JSmart523 --> 
    Called by New 
%END REM 
Sub InitFileItem() 
    Dim buffer As Variant 'byte array 
    Dim iFileNameLen As Integer 
    Dim sFileName As String 
    Dim sItemName As String 
    Dim stream As NotesStream 

    If Len(m_b64) < 30000 Then 
     'If content is short then maybe it's a link to a $FILE item instead of the actual content? 
     Dim session As New NotesSession 
     Set stream = session.CreateStream() 
     Base64ToBinary m_b64, stream 
     stream.Position = 0 
     buffer = stream.Read(1) 
     If buffer(0) = 196 Then 
      'this is a link to a $FILE, not the actual image contents! 

      stream.Position = 10 
      buffer = stream.Read(2) 
      iFileNameLen = ConvertWordByteArray(buffer) 

      stream.Position = 24 
      buffer = stream.Read(iFileNameLen) 
      sFileName = BytesToString(buffer) 
      sItemName = "$FILE" 

      GetFileItem sItemName, sFileName 'sets m_fileItem to a FileItem object 
     End If 
    End If 
End Sub 

%REM 
    Property Get SuggestedFileName 
%END REM 
Public Property Get SuggestedFileName As String 
    If m_fileItem Is Nothing Then 
     SuggestedFileName = "Embedded-" + ItemName + "." + SuggestedFileType 
    Else 
     SuggestedFileName = m_fileItem.FileName 
     If InStr(SuggestedFileName, ".") = 0 Then 
      SuggestedFileName = SuggestedFileName + "." + SuggestedFileType 
     End If 
    End If 
End Property 

%REM 
    Property Get SuggestedFileType 
%END REM 
Public Property Get SuggestedFileType As String 
    If ImageType = "notesbitmap" Then 
     SuggestedFileType = "bmp" 
    Else 
     SuggestedFileType = ImageType 
    End If 
End Property 

%REM 
    Sub ReadFileToStream 
%END REM 
Sub ReadFileToStream(streamOut As NotesStream) 
    If m_FileItem Is Nothing Then 
     ReadToStream streamOut 
    Else 
     Set m_FileItem.Stream = streamOut 
     m_FileItem.Load 
    End If 
End Sub 

,然後更改EmbeddedItem.New到,到了最後,調用InitFileItem所以,如果它是一個鏈接然後獲取內容返回的內容,而不是鏈接。

好的,據我所知目前爲止還不錯,但問題在於CD文件存儲在$ FILE項目中(即富文本字段的嵌入式圖像節點僅包含鏈接而非實際圖像) /儘管AGECOM的代碼和解釋對我來說是無法穿透的。我可以使用上面的代碼和Andre的EmbeddedImageList對象來抓取每一個嵌入的圖像,但是我根本無法得到一個「ConvertOldCDToNew」方法,因此我無法將舊的CD Record格式轉換爲可靠,無損的文件!我不知道我是否剝離了太多的字節,沒有剝離正確的字節,或者我只是forgot to carry the two