Capture embedded files with the OneNote API

Learn how to embed files in captured OneNote notebook pages using the <object> tag with Microsoft OneNote API.

Last modified: January 22, 2016

Applies to: OneNote service

In this article
Embed files on a page in an Android app
Embed files on a page in an iOS app
Embed files on a page in a Windows Phone app
Embed files on a page in a Windows Store app
Embed files on a page using REST

Note Note

See this content on our new documentation site for consumer and enterprise OneNote APIs.

The OneNote API lets you display several different kinds of images on your pages: GIF, JPEG, TIFF, PNG, and so on. What do you do when you want to capture a file on the page and have it displayed like an embedded file, represented by an icon? In this scenario, use the <object> tag in your captured HTML, and transmit the file data in a multi-part message part. The following code shows how the HTML <object> tag might look.


<html>
  <head>
    <title>A page with an embedded file</title>
  </head>
    <body>
      <p>Attached is my cat&apos;s autobiography.</p>
      <object 
        data-attachment="MyCatAutobiography.docx" 
        data="name:CatBioPartName" 
        type="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
    </body>
</html>

The <object> tag requires the following attributes:

  • data-attachment="embeddedFilename.ext" sets the file name and extension displayed on the OneNote page.

  • data="name:multiPartBlockName" gives the part name in the request that contains the binary file contents. The OneNote API does not support passing a URL reference here.

  • type="standardMimeType" indicates the file MIME type. This is used to select the file icon on the page, and also determines which application starts when the user activates the file on the device from OneNote.

Remember these limits when you're embedding files in a OneNote API capture. We're working to remove or expand these limits, but for now they are:

  • Total POST size limit is ~70 MB, including file and other data. Captures with data more than that limit may make your app and captures unreliable, so be careful.

  • MIME part size limit is 25 MB. Larger data blocks will be rejected by the API. This applies to both images and file-data parts, and the size include the part headers.

  • Image limit is 30 per page. When using the src="internetURL"/> attribute, the API ignores <img> tags beyond the limit.

  • MIME parts limit is 6 per POST. That includes the Presentation HTML part.

  • Maximum number of <img/> and <object/> tags using data-render-src is 5. Additional rendered images and embedded files are ignored.

  • File-type icons are predefined. The OneNote API recognizes a wide variety of common file types, and embeds the file using predefined icons. If the API doesn't recognize the file type, it uses a generic file icon.

For more information about the object tag, see https://msdn.microsoft.com/en-us/library/office/dn575442.aspx.

Important noteImportant

Before POST requests like the ones shown here can succeed, Get a client ID for use with the OneNote API (or package ID for a Windows Store application), and your app has to Authenticate the user for the OneNote API. If you don't supply a valid OAuth token with your request, it will fail.

TipTip

These code samples should not be considered production-ready code. Things like detailed user-input validation have been left out to make it easier to understand the code flow. Carefully review your code for potential code-quality and security issues before you publish your app.

The following code sample builds a multi-part request that contains a "Presentation" part with HTML, and a second part with binary file data. In this example, a logo image file is compiled into the app, and will be inserted into the page as an embedded file.

In this code sample, the binary image data is passed to this member as the imageBinaryAsString parameter. The createPageWithImage function is adapted from the SendPageCreateAsyncTask class in the Android sample on Github. For more information, see Get the OneNote API sample applications.

public ApiResponse createPageWithImage(String imageBinaryAsString) 
{
  try {
    this.connectForMultipart(PAGES_ENDPOINT);
    String date = getDate();
    String imagePartName = "image1";
    String onml = "<html>" +
      "<head>" +
      "<title>A page with an image on it (Android Sample)</title>" +
      "<meta name=\"created\" content=\"" + date + "\" />" +
      "</head>" +
      "<body>" +
      "<h1>This is a page with an image on it</h1>" +
      "<object data-attachment=\"Logo.jpg\" " +
      "data=\"name:" + imagePartName + "\" type=\"image/jpeg\" />" +
      "</body>" +
      "</html>";
    this.addFormPart("Presentation", "application/xhtml+xml", onml);
    this.addFormPart(imagePartName, "image/jpeg", imageBinaryAsString);
    this.finishMultipart();
    ApiResponse response = this.getResponse();
      return response;
  } catch (Exception ex) {
    String test = ex.getMessage();
  }
  return null;
}

The following code sample builds a multi-part request that contains a "Presentation" part with HTML, and a second part with binary image data, that will be inserted into the page as an embedded file. In this example, a logo image is compiled into the app, but the technique is the same for other files.

This code is adapted from the ONSCPSCreateExamples class in the iOS code sample on GitHub. For more information, see Get the OneNote API sample applications.


- (void)createPageWithImage {
    NSString *date = [ONSCPSCreateExamples getDate];
    UIImage *logo = [UIImage imageNamed:@"Logo"];
    NSString *simpleHtml = [NSString stringWithFormat:
        @"<html>"
        "<head>"
        "<title>A simple page with an image from iOS</title>"
        "<meta name=\"created\" content=\"%@\" />"
        "</head>"
        "<body>"
        "<h1>This is a page with an image on it</h1>"
        "<object data-attachment=\"Logo.jpg\" "
        "data=\"name:image1\" type=\"image/jpeg\" />"
        "</body>"
        "</html>", date, [logo size].width, [logo size].height];
    NSData *presentation = [simpleHtml dataUsingEncoding:NSUTF8StringEncoding];
    NSData *image1 = UIImageJPEGRepresentation(logo, 1.0);
    
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] 
      multipartFormRequestWithMethod:@"POST" URLString:PagesEndPoint parameters:nil 
      constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
        [formData
          appendPartWithHeaders:@{
            @"Content-Disposition" : @"form-data; name=\"Presentation\"",
            @"Content-Type" : @"text/html"}
          body:presentation];
        [formData
          appendPartWithHeaders:@{
            @"Content-Disposition" : @"form-data; name=\"image1\"",
            @"Content-Type" : @"image/jpeg"}
           body:image1];
    }];
    if (liveClient.session)
    {
        [request setValue:[@"Bearer " 
          stringByAppendingString:liveClient.session.accessToken] 
          forHTTPHeaderField:@"Authorization"];
    }
    currentConnection = [[NSURLConnection alloc] 
      initWithRequest:request delegate:self startImmediately:YES];
}

The following code sample builds a multi-part request that contains a "Presentation" part with HTML, and a second part with binary image data, that will be inserted into the page as an embedded file. In this example, a logo image is compiled into the app, but the technique is the same for other files.

        
private async void btn_CreateWithImage_Click(object sender, RoutedEventArgs e)
{
  StartRequest();
  var client = new HttpClient();

  // Note: API only supports JSON return type.
  client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));
  // This allows you to see what happens when an unauthenticated call is made.
  if (m_AccessToken != null)
    {
      client.DefaultRequestHeaders.Authorization = 
        new AuthenticationHeaderValue("Bearer", m_AccessToken);
    }

  const string imagePartName = "image1";
  string date = GetDate();
  string simpleHtml = "<html>" +
    "<head>" +
    "<title>A page with an image on it (WinPhone8 Sample)</title>" +
    "<meta name=\"created\" content=\"" + date + "\" />" +
    "</head>" +
    "<body>" +
    "<h1>This is a page with an image on it</h1>" +
    "<object data-attachment=\"name:" + imagePartName + "\" " +
    "type=\"image/jpeg\" />" +
    "</body>" +
    "</html>";

  // Create the image part – be sure it is disposed after we've sent 
  // the message to close the stream.
    HttpRequestMessage createMessage = null;
    HttpResponseMessage response = null;
    Stream imageStream = await GetImageStream("assets\\Logo.jpg");
    using (var imageContent = new StreamContent(imageStream))
      {
        imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
        createMessage = new HttpRequestMessage(HttpMethod.Post, PAGESENDPOINT)
      {
    Content = new MultipartFormDataContent
      {
        { 
          new StringContent(simpleHtml, System.Text.Encoding.UTF8, 
            "text/html"), "Presentation"},
            {imageContent, imagePartName}
        }
      };
    // Must send the request within the using block, or the 
    // image stream will have been disposed.
    response = await client.SendAsync(createMessage);
  }
  await EndRequest(response);
}

The following code sample builds a multi-part request that contains a "Presentation" part with HTML, and a second part with binary image data, and will be inserted into the page as an embedded file. In this example, a logo image is compiled into the app, but the technique is the same for other files.


async public Task<StandardResponse> CreatePageWithImage(bool debug)
{
  var client = new HttpClient();
  // Note: API only supports JSON return type.
  client.DefaultRequestHeaders.Accept.Add( 
    new MediaTypeWithQualityHeaderValue("application/json"));
  // This allows you to see what happens when an unauthenticated call is made.
  if (this.IsAuthenticated)
  {
    client.DefaultRequestHeaders.Authorization = 
      new AuthenticationHeaderValue("Bearer", 
      this._authClient.Session.AccessToken);
  }
  const string imagePartName = "image1";
  string date = GetDate();
  string simpleHtml = "<html>" +
    "<head>" +
    "<title>A simple page created with an image on it</title>" +
    "<meta name=\"created\" content=\"" + date + "\" />" +
    "</head>" +
    "<body>" +
    "<h1>This is a page with an image on it</h1>" +
    "<object data-attachment=\"name:" + imagePartName + "\" " +
    "type=\"image/jpeg\" />" +
    "<img src=\"name:" + imagePartName + 
    "\" alt=\"A beautiful logo\" width=\"426\" height=\"68\" />" +
    "</body>" +
    "</html>";
  // Create the image part - be sure it is disposed after 
  // we've sent the message in order to close the stream.
  HttpRequestMessage createMessage = null;
  HttpResponseMessage response = null;
  using (var imageContent = new StreamContent( 
    await GetImageStream("assets\\Logo.jpg")))
    {
      imageContent.Headers.ContentType = 
        new MediaTypeHeaderValue("image/jpeg");
      createMessage = new HttpRequestMessage(HttpMethod.Post, PagesEndPoint)
        {
          Content = new MultipartFormDataContent
            {
              { 
                new StringContent(simpleHtml, 
                System.Text.Encoding.UTF8, "text/html"), "Presentation"
              },
              {imageContent, imagePartName}
            }
        };
      // Must send the request within the using block, or the 
      // image stream will have been disposed.
      response = await client.SendAsync(createMessage);
    }
  return await TranslateResponse(response);
}

If your app is running in a mobile device, scanner or camera, and you want to embed files in OneNote pages, you will want to upload the file data directly to the API from the device. You do this by embedding the file data in a multi-part message, with separate parts for each file.

In the HTML of your request "Presentation" part, include an object tag. In the object tag data attribute, use the special syntax "name:RequestBlockPartId", where RequestBlockPartId is an alphanumeric identifier of a part in your multi-part request. This next code example shows how to do that, using the string as the identifier.


Content-Type:multipart/form-data; boundary=MyAppPartBoundary
Authorization:bearer tokenString

--MyAppPartBoundary
Content-Disposition:form-data; name="Presentation"
Content-type:text/html

<!DOCTYPE html>
<html>
  <head>
    <title>A simple page with an embedded file</title>
  </head>
  <body>
    <p>This is a simple Presentation block.</p>
    <p>This next object tag specifies the file data in this POST request.</p>
    <object data-attachment="Logo.jpg" data="name: MyAppFileBlockName" 
      type="image/jpeg" />
  </body>
</html>

--MyAppPartBoundary
Content-Disposition:form-data; name=" MyAppFileBlockName"
Content-type:image/jpeg

... embedded file binary data ...

--MyAppPartBoundary--


To embed multiple objects this way, each image Id has to be unique within the POST request.

The image data is the binary file data; don't use Base64 or otherwise encode it.

Show: