Embedding Watermarks into Images During Upload to a Picture Library on a SharePoint Site

 

Alexander Windel
Microsoft Corporation

December 2003

Applies to:
     Microsoft® Windows® SharePoint™ Services
     Microsoft Office SharePoint Portal Server 2003

Summary: Simplify copyright protection for your picture library images with built-in Web services for Microsoft SharePoint Products and Technologies. This article describes how to create a sample client application allowing you to embed watermarks into images when uploading them to a picture library on a SharePoint site.

This article assumes that you have a basic understanding of the Microsoft .NET Framework and a programming language such as Microsoft Visual Basic®.NET. For additional reference material not included in this article, see the Microsoft SharePoint Products and Technologies Software Development Kit (SDK). (14 printed pages)

Note   The information in this article also applies to Microsoft Office SharePoint Portal Server 2003, which is built on the Windows SharePoint Services platform.

Contents

Introduction
Creating the Watermark Application
Conclusion

Introduction

Microsoft® Windows® SharePoint™ Services includes many built-in Web services offering new, powerful ways to integrate business processes. At the same time, copyright is an issue which is getting more and more important for enterprises.

Using the Imaging Web service in a sample application provides a great way to automate the complete process of retrieving images from local or remote sources, embedding a unique watermark into these images and then, populating a picture library with those customized images.

You must be a member of the Contributor site group on the server that is running Windows SharePoint Services to run the watermark Web service client for the Imaging Web service on an existing picture library. To create the picture library on the SharePoint site, you must be a member of the Web Designer site group. To compile the sample application without customizations, you need to download the Microsoft .NET Framework version 1.1. Microsoft Visual Studio® .NET 2003 already includes this version of the Microsoft .NET Framework.

The following list outlines the process for retrieving images, embedding a watermark, and uploading them to a picture library by using Web services. The remainder of the article reviews this process in detail.

  • Using Visual Studio .NET, create a Windows Application Project, write code to scan your computer for local image files and populate a ListView control with the results. If required, add remote image files, for example from another Web service on the WWW, to your local list of pictures.
  • Write code to embed a unique watermark, e.g. based on the current user name, into the images by taking advantage of the DrawString method.
  • Generate a Web service proxy class for your Imaging Web service by adding a Web Reference in Visual Studio .NET. The Web service URL should be similar to: http://server_name/_vti_bin/Imaging.asmx
  • Make sure that your picture library exists, and then use the Upload Web method to transfer the images to the picture library.

Creating the Watermark Application

To create a sample watermark application for a picture library, use the following methods in the order in which they are presented.

To create the GUI of the sample Windows Application Project in Visual Studio .NET 2003

  1. On the File menu, point to New, and then click Project.

  2. In the Project Types box, click Visual Basic Projects.

  3. In the Templates box, click Windows Application.

  4. Specify a name and location for the project and then click OK.

  5. In the Toolbox window, add a MainMenu and a TabControl component to Form1. By default these controls are named MainMenu1 and TabControl1.

  6. In the Properties window of the TabControl control, open the TabPage Collection Editor and configure the TabPage collection to have two members, TabPage1 and TabPage2.

  7. Change the Text property of TabPage1 to Local image source and rename the Text property of TabPage2 to Remote Image source.

  8. In the Design Window for****Form1, click MainMenu1 and then click the Type here box on the menu bar.

  9. Add three top-level menu items.

  10. In the Type here box for each item, add the following descriptions:

    • For item 1 type, Explore current batch folder content.
    • For item 2 type, Start batch upload to picture library.
    • For item 3, type, Exit.
  11. Add three LinkLabel controls to TabPage1.

  12. Change the Text property of the LinkLabel1 to Start Scanning.

  13. Change the Text property of the LinkLabel2 to Stop Scanning.

  14. Change the Text property of LinkLabel3 to Copy Selected Images to Batch Folder.

  15. Add one Label control, one Button control, and a ListView control to TabPage1.

  16. Change the Text property of Label1 to Processing. . . and in the Properties window, set the Visible property to False at Design time.

  17. Change the Text property of Button1 to Change folder.

  18. Change the View property of ListView1 to List.

    Figure 1. First tab of completed form

  19. Add a FolderBrowserDialog control to Form1.

    Note   The FolderBrowserDialog control requires the Microsoft .NET Framework version 1.1.

  20. Add a PictureBox control, a Label control, a LinkLabel control and a TextBox control to TabPage2.

  21. Place Label2 above the TextBox1 control.

  22. Change the Text property of Label2 to Scale and the Text property of LinkLabel4 to Get image from database.

  23. Set the Text property of TextBox1 to 0.396127. This determines the scale of the retrieved image in arcsec/pixel.

    Figure 2. Second tab of completed form

    Note   Depending on your regional options you may need to modify the string to use a comma instead of a period, leading to 0,396127 as the default value.

You can now add the code to scan for local images or retrieve remote images.

To scan for image files and copy them to the Batch Upload folder

  1. Add the following imports directive to your Windows Application project.

    Imports System.IO
    
  2. We need a Boolean variable for LinkLabel2 functionality such as Stop scanning to work. Therefore, add the following declaration to the Form1 class.

    Dim interrup As Boolean
    
  3. We also need a procedure which accepts a path string and then searches all files and subfolders for existing image files. Add the following recursive procedure to the Form1 class code to accomplish this requirement.

    Private Sub SearchImages(ByVal Path As String)
       If interrup Then Exit Sub
       Try
          Dim fInfo As FileInfo
          Dim dInfo As DirectoryInfo
          Dim currdir As DirectoryInfo = New DirectoryInfo(Path)
          Dim mydirectories() As DirectoryInfo = currdir.GetDirectories
          Dim myfiles() As FileInfo = currdir.GetFiles
    
          For Each dInfo In mydirectories
             SearchImages(dInfo.FullName)
          Next
          For Each fInfo In myfiles
             If interrup = False Then
                If LCase(fInfo.Extension) = ".gif" _ 
                   Or LCase(fInfo.Extension) = ".bmp" _
                   Or LCase(fInfo.Extension) = ".jpg" _
                   Or LCase(fInfo.Extension) = ".jpeg" _
                   Or LCase(fInfo.Extension) = ".png" _
                   Or LCase(fInfo.Extension) = ".tif" _
                   Or LCase(fInfo.Extension) = ".tiff" _
                   Or LCase(fInfo.Extension) = ".gif" _ 
                   Or LCase(fInfo.Extension) = ".pcd" _ 
                   Or LCase(fInfo.Extension) = ".pcx" _
                Then 
                   ListView1.Items.Add(fInfo.FullName)
                End If
             Else
                Exit For
             End If
             Application.DoEvents()
          Next
       Catch xx As Exception
          MessageBox.Show(xx.Message, "Error", _ 
          MessageBoxButtons.OK, MessageBoxIcon.Error)
       End Try
    End Sub
    
  4. In the Load event procedure for Form1, add the following code.

    Note   This procedure sets the defaults of FolderbrowserDialog1.SelectedPath and LinkLabel1.Text to point to the My Pictures folder. If necessary, it creates the ImagesToBeShared folder that contains all the files to be uploaded in a batch to the specified picture library as specified by the URL property of the Imaging Web service. The usage of Environment.SpecialFolder.MyPictures as well as the FolderBrowserDialog control requires the Microsoft .NET Framework version 1.1.

    Dim drives() As String
    Dim mypic As String
    Try
       mypic = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
       FolderBrowserDialog1.SelectedPath = mypic
       LinkLabel1.Text = "Start Scanning " & FolderBrowserDialog1.SelectedPath
       If Not (Directory.Exists(mypic & "\ImagesToBeShared")) Then
       Directory.CreateDirectory(mypic & "\ImagesToBeShared")
       End If
    Catch xx As Exception
       MessageBox.Show(xx.Message, "Error", _ 
       MessageBoxButtons.OK, MessageBoxIcon.Error)
       End
    End Try
    
  5. In the LinkClicked event procedure for LinkLabel1, add the following code.

    Note   If you click the LinkLabel1 ("Start scanning") the selected local path and all of its subdirectories are searched for image files by calling the SearchImages procedure.

    Try
       interrup = False
       ListView1.Visible = False
       Label1.Visible = True
       ListView1.Items.Clear()
       Me.Cursor = Cursors.WaitCursor
       SearchImages(FolderBrowserDialog1.SelectedPath.ToString)
       ListView1.Visible = True
       Me.Cursor = Cursors.Default
       Label1.Visible = False
       If ListView1.Items.Count <= 0 Then
               MessageBox.Show("No files were found!", _ 
    "File not found", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
       Else
    MessageBox.Show("Scanning finished.", "Done", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Information)
         End If
    Catch xx As Exception
       MessageBox.Show(xx.Message, "Error", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Error)
    Finally
       ListView1.Visible = True
       Label1.Visible = False
       Me.Cursor = Cursors.Default
    End Try
    
  6. In the LinkClicked event procedure for LinkLabel2, add the following code.

    Note   This indicates to the SearchImages procedure that local file searching should be cancelled.

    interrup = True
    
  7. We need some code to copy all selected items from ListView1 to the image batch folder at . . .\My Pictures\ImagesToBeShared. In the LinkClicked event procedure for LinkLabel3, we therefore add the following code:

    Dim PicDir As String
    Dim LItem As ListViewItem
    Dim LItems As ListView.SelectedListViewItemCollection
    Dim i As Integer
    
    Try
       PicDir = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
       If Not (Directory.Exists(PicDir & "\ImagesToBeShared")) _
    Then
          Directory.CreateDirectory(PicDir & "\ImagesToBeShared")
       End If
       If ListView1.SelectedItems.Count <= 0 Then
          MessageBox.Show("No Items selected!", _
    "Item not found", MessageBoxButtons.OK, MessageBoxIcon.Error)
          Exit Try
       End If
       LItems = ListView1.SelectedItems
       Me.Cursor = Cursors.WaitCursor
       For i = 0 To LItems.Count - 1
          Try
             LItem = LItems(i)
             File.Copy(LItem.Text.ToString, PicDir & _ 
    "\ImagesToBeShared\" & _ 
    Path.GetFileName(LItem.Text.ToString))
          Catch xx As Exception
             MessageBox.Show(xx.Message, "Error", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Error)
          End Try
       Next
       Me.Cursor = Cursors.Default
    MessageBox.Show("Finished copying files to " _ 
    & PicDir & "\ImagesToBeShared.", "Done", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Information)
    Catch xx As Exception
    MessageBox.Show(xx.Message, "Error", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Error)
    Finally
       Me.Cursor = Cursors.Default
    End Try
    ListView1.Items.Clear()
    
  8. In the Click event procedure for Button1, add this code.

    Try
       FolderBrowserDialog1.ShowDialog()
    LinkLabel1.Text = _ 
    "Start Scanning " & FolderBrowserDialog1.SelectedPath
    Catch xx As Exception
       MessageBox.Show(xx.Message, _ 
    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Try
    
  9. Now that we added the required code to copy local image files to our Upload folder, we want to add some remote images, too. For the sample code to work, add a Web reference to the Image CutOut Web service of the publicly available Sky Digital Space Survey (SDSS) database. For more information about the SDSS database we make use of here, see SDSS SkyServer.

  10. In Solution Explorer, right-click the project, and then click Add Web Reference.

  11. In the wizard, type the following URL, and then click Open to download the service contract for the Web service:

    http://skyservice.pha.jhu.edu/dr1/ImgCutout/imgcutout.asmx

    Note   While adding the Web reference, if you receive the error message "The underlying connection was closed: The remote name could not be resolved" then you need to modify the proxy settings in your machine.config file. For more information, see the following articles:

    Microsoft Knowledge Base Article--318140: PRB: Error on .NET Client that Consumes a Web Service through an HTTP Proxy Server

    Microsoft Knowledge Base Article--307220: HOW TO: Configure an XML Web Service Client by using the .NET Framework to Work with a Proxy Server

  12. Name this Web reference SDSS_Images.

  13. Now we need add code that adds an image from the Image CutOut Web service to PictureBox1. For the sake of simplicity, we assign fixed values to most of the variables except the scale of the image retrieved. With regard to the location in space, ra is the right ascension and dec is the declination in degrees. The imageoptions value is set to return a grid and some descriptive labels as part of the image. Add the code below to the LinkClicked event procedure of LinkLabel4.

    Try
       Dim JpgContent() As Byte
       Dim JpgStream As FileStream
       Dim res As DialogResult
       Dim PicDir As String
       Dim jpgname As String
    
       Dim ra As Double = 184.9511
       Dim dec As Double = -0.8754
       Dim imagewidth As Integer = 350
       Dim imageheight As Integer = 350
       Dim imageoptions As String = "GL"
       Dim scale As Double
    
       If IsNumeric(TextBox1.Text) Then
          scale = CDbl(TextBox1.Text)
       Else
          scale = 0.396127
       End If
          Dim SpaceImages As New SDSS_Images.ImgCutout
          SpaceImages.Timeout = 20000
          PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
          jpgname = _ 
    InputBox("Choose file name without extension: ", _ 
    "New file name") 
    If jpgname = "" Then Exit Try
          jpgname = Path.GetFileNameWithoutExtension(jpgname) & ".jpg"
          PicDir = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
          If Not (Directory.Exists(PicDir & "\ImagesToBeShared")) Then
               Directory.CreateDirectory(PicDir & "\ImagesToBeShared")
          End If
          If File.Exists(PicDir & "\ImagesToBeShared\" & jpgname) Then
             MessageBox.Show("File already exists", _ 
             "File already exists", MessageBoxButtons.OK, _
             MessageBoxIcon.Error)
             Exit Try
          Else
             Me.Cursor = Cursors.WaitCursor
             JpgStream = File.Create(PicDir & _ 
             "\ImagesToBeShared\" & jpgname)
          End If
          JpgContent = SpaceImages.GetJpeg(ra, dec, scale, imagewidth _ 
    , imageheight, imageoptions)
          Dim w As New BinaryWriter(JpgStream)
          w.Write(JpgContent)
          JpgStream.Close()
          w.Close()
          PictureBox1.Image = PictureBox1.Image.FromFile(PicDir _ 
          & "\ImagesToBeShared\" & jpgname)
          PictureBox1.Refresh()
          Me.Cursor = Cursors.Default
    Catch xx As Exception
          MessageBox.Show(xx.Message, "Error", MessageBoxButtons.OK, _
          MessageBoxIcon.Error)
    Finally
          Me.Cursor = Cursors.Default
    End Try
    
  14. In the Click event procedure for MenuItem1, add the following code.

    Dim ProcID As Integer
    Try
    ProcID = Shell("explorer.exe " & _ 
    Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) & _ 
    "\ImagesToBeShared", AppWinStyle.NormalFocus)
    Catch xx As Exception
       MessageBox.Show(xx.Message, "Error", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Try
    
  15. Add a Web reference to the Imaging Web service.

    1. Right-click the project in Solution Explorer, and then click Add Web Reference.

    2. In the wizard, type the following URL, and then click Open to download the service contract for the Web service:

      http://Server_name/_vti_bin/Imaging.asmx

  16. Name this Web reference ImagingService.

  17. In the Click event procedure for MenuItem2, add the following code.

    Note   This instantiates an ImageList object of the proxy class of the Imaging Web service for the SharePoint site and uses the DrawString method on a Graphics object to add watermarks. The color of the SolidBrush object being applied to the watermarks is chosen for use with images with a dark background such as those retrieved from the SDSS Web service. Last but not least the procedure invokes the Upload Web method to transfer all images of the Watermark folder to the root folder of the picture library named Shared Images. Existing files are overridden as specified by the fOverwriteIfExist parameter of the method. The time-out value is set to 20 seconds to prevent network bottleneck issues. The Credentials property is configured to use default credentials, e.g. Integrated Windows Authentication.

    Dim PicDir As String
    Dim i As Long
    Dim AllFiles() As String
    Dim FStream As FileStream
    Dim res As DialogResult
    Dim wm As String
    
    Try
       Dim ImageList As New ImagingService.Imaging
       PicDir = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
       If Not (Directory.Exists(PicDir & "\ImagesToBeShared")) Then
          Directory.CreateDirectory(PicDir & "\ImagesToBeShared")
          MessageBox.Show("WSS Batch Upload directory not found" & _ 
    "- recreated directory!", "Directory not found", _ 
    MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
          Exit Try
       End If
       If Directory.GetFiles(PicDir & "\ImagesToBeShared").Length = 0 _
       Then
          MessageBox.Show("No files to upload!", "File not found", _ 
          MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
          Exit Try
       End If
       AllFiles = Directory.GetFiles(PicDir & "\ImagesToBeShared")
       res = MessageBox.Show("Your files will be uploaded to " & _ 
       ImageList.Url.ToString & ". Proceed?", "Confirm Upload", _ 
       MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
       If res = DialogResult.OK Then
          ImageList.Credentials = _ 
          System.Net.CredentialCache.DefaultCredentials
          ImageList.Timeout = 20000
          Me.Cursor = Cursors.WaitCursor
          If Not Directory.Exists(PicDir & "\watermark") Then
             Directory.CreateDirectory(PicDir & "\watermark")
          End If
          PictureBox1.Visible = False
          PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
          For i = 0 To AllFiles.Length - 1
             Try
                PictureBox1.Image = _ 
                PictureBox1.Image.FromFile(AllFiles(i).ToString)
                Dim bmp As New _ 
                Bitmap(PictureBox1.Width, PictureBox1.Height)
                bmp.SetResolution(PictureBox1.Image.HorizontalResolution, _ 
                PictureBox1.Image.VerticalResolution)
                Dim gra As Graphics = Graphics.FromImage(bmp)
                gra.DrawImage(PictureBox1.Image, 0, 0)
                gra.DrawString(Environment.UserName, _ 
                PictureBox1.Font, New _ 
                SolidBrush(Color.FromArgb(130, 255, 0, 0)), 0, 0)
                gra.Dispose()
                wm = PicDir & "\watermark\" & _ 
                Path.GetFileName(AllFiles(i).ToString)
                bmp.Save(wm)
                bmp.Dispose()
                FStream = File.OpenRead(wm)
                Dim r As New BinaryReader(FStream)
                Dim FContent(FStream.Length - 1) As Byte
                FContent = r.ReadBytes(FStream.Length)
                ImageList.Upload("Shared Images", "", _ 
    FContent, Path.GetFileName(wm), True)
                r.Close()
             Catch xx As Exception
                MessageBox.Show("The file " & AllFiles(i).ToString & " cannot be processed.", "Warning", _ 
                MessageBoxButtons.OK, MessageBoxIcon.Warning)
             End Try
          Next
             PictureBox1.Visible = True
             Me.Cursor = Cursors.Default
             MessageBox.Show("Uploading files finished.", _
             "Done", MessageBoxButtons.OK, MessageBoxIcon.Information)
       End If
    Catch xx As Exception
       MessageBox.Show(xx.Message, "Error", MessageBoxButtons.OK, _
       MessageBoxIcon.Error)
    Finally
       Me.Cursor = Cursors.Default
       PictureBox1.Visible = True
    End Try
    
  18. In the Click event procedure for MenuItem3, add the following line of code.

    End
    
  19. Now we've got all necessary code to run our sample. Compile the project. Before running the sample application, verify that a picture library named Shared Images exists on the SharePoint site and that you have the necessary permissions for the picture library.

Conclusion

In this article you learned how you can effectively integrate the Upload web method of the Imaging Web service of Windows SharePoint Services into a sample application allowing you to embed watermarks into images at upload time. Using watermarks for your picture libraries as a method to ensure copyright enhances the power and security of data stored on a SharePoint site.