• Solutions
    • FERC XBRL Reporting
    • FDTA Financial Reporting
    • SEC Compliance
    • Windows Clipboard Management
    • Legato Scripting
  • Products
    • GoFiler Suite
    • XBRLworks
    • SEC Exhibit Explorer
    • SEC Extractor
    • Clipboard Scout
    • Legato
  • Education
    • Training
    • SEC and EDGAR Compliance
    • Legato Developers
  • Blog
  • Support
  • Skip to blog entries
  • Skip to archive page
  • Skip to right sidebar

Friday, July 06. 2018

LDC #92: Capturing Images from the Clipboard

Occasionally I have had the need to serially capture images for later use. There are a number of utilities available, some free, with varying capabilities, that do this. Recently I was asked to try get download a bunch of photos from a site that had no simple way to download images. To accomplish this, I wrote a little script that lets a user capture images, presumably from a screenshot or from a right-click “Copy” command, and serially store them.


A picture next to a clipboard with the same imageWithin Legato there is a function that directs Windows to add the current dialog page to the clipboard chain. The clipboard chain is a series of windows that can receive a notification regarding the clipboard contents changing. Each window in the chain is notified anytime the content of the clipboard is altered. The ClipboardAttachDialog function both attaches and releases a dialog page:


int = ClipboardAttachDialog ( [boolean release] );


If the release parameter is not supplied, the dialog page is attached. If the parameter is supplied as TRUE, then the attach is discontinued. When a dialog page closes, the attachment is automatically removed.


Once attached, the dialog procedure “clipboard_change” is called every time the clipboard changes.


The Capture Script


Our sample script is very simple. It sets up the dialog and the clipboard and waits. The location where the captured image data is stored is preprogrammed as ‘Legato Image Capture’ on the user desktop.


                                                                // Monitor Dialog Resource
#beginresource

#define SC_CHANGES              101
#define SC_COUNT                102
#define SC_STATUS               103

CaptureDlg DIALOGEX 0, 0, 140, 44
EXSTYLE WS_EX_DLGMODALFRAME
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Image Capture"
FONT 8, "MS Shell Dlg"
{
CONTROL "Clipboard Changes:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 12, 6, 80, 8, 0
CONTROL "(none)", SC_CHANGES, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 80, 6, 30, 8, 0
CONTROL "Saved Images:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 12, 18, 80, 8, 0
CONTROL "(none)", SC_COUNT, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 80, 18, 30, 8, 0
CONTROL "", SC_STATUS, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 12, 30, 120, 8, 0
}

#endresource

                                                                // Global Data
    string              fnBase;
    string              fnName;

    int                 cc;
    int                 ic;


int main() {

    fnBase = GetDesktopFolder() + "Legato Image Capture\\";
    fnName = "Image %03d.jpg";
    CreateFolders(fnBase);

    cc = -1;

    DialogBox("CaptureDlg", "ic_");
    
    return ERROR_NONE;
    }
    
    
int ic_load() {                                                 // Load Controls/Initialize
    ClipboardAttachDialog();
    return ERROR_NONE;
    }
    
int ic_clipboard_change() {                                     // Clipboard Notification
    handle              hDIB, hImage;
    string              s1;
    int                 rc;

    cc++;
    if (cc == 0) { return ERROR_NONE; }
    EditSetText(SC_CHANGES, cc);

    if (ClipboardIsDIBAvailable() == FALSE) { return ERROR_NONE; }

    ic++;
    EditSetText(SC_COUNT, ic);

    hDIB = ClipboardGetDIB();
    if (hDIB == NULL_HANDLE) { 
      EditSetText(SC_STATUS, "Error %08X ClipboardGetDIB", GetLastError());
      return ERROR_NONE;
      }

    hImage = ImageLoad(hDIB);
    if (hImage == NULL_HANDLE) { 
      EditSetText(SC_STATUS, "Error %08X ImageLoad", GetLastError());
      return ERROR_NONE;
      }
    
    s1 = fnBase + FormatString(fnName, ic);
    rc = ImageExportJPEG(hImage, s1);
    if (IsError(rc)) { 
      EditSetText(SC_STATUS, "Error %08X ImageExportJPEG", rc);
      return ERROR_NONE;
      }

    return ERROR_NONE;
    }

The first part of the script is a little dialog that has three display fields: the number of clipboard changes; the number of images saved; and a field for error messages. Note that the count fields are preloaded with ‘(none)’ so that, when first started, the dialog display as follows:


Image Capture Dialog


As changes are processed, the dialog changes:


Image Capture Dialog with captured images


We will come back to the dialog in a moment. There are four global variables defined:


    string              fnBase;
    string              fnName;

    int                 cc;
    int                 ic;

The base refers the path which is set to a folder in the user desktop. The name is also a base of sorts; since the images are numbered, it needs to have a formatted number value such as ‘%03d’ to place the image count. Note that this script will create the folder and overwrite the contents on each run. You can add logic to protect against overwrites, if desired.


The cc and ic track the ‘clipboard changes’ and the ‘image count’. You will later note that the cc is initialize to -1 because the clipboard procedure is called as the dialog is attached to the chain. So the chain procedure accommodates this to avoid a first false hit.


The main function sets up the path, the name, sets and initial change count and then launches the dialog. The load function of the dialog simply performs the clipboard attach using the ClipboardAttachDialog function.


Primary processing lies in the ic_clipboard_change function. This part counts the clipboard changes and displays the result in the SC_CHANGES static text control. If an image format has not been posted to the clipboard, the function exits:


if (ClipboardIsDIBAvailable() == FALSE) { return ERROR_NONE; }


After which the image count is updated. The function then gets the image as a DIB (Device Independent Bitmap). This works for many image sources but not all. Since I was interested in capturing screenshots, it works in this case. To expand this, one would have to look at retrieving other formats such as PNG, JPEG or GIF and then selecting which to store.


The DIB is loaded into an Image Object. This gives us option to export the data in a number of formats. Since our filename has a .jpg extension, the images are exported as JPEGs.


Finally, upon exit of the function, all the handles will be released and the code ready for the next clipboard change.


Conclusion


When the script is operating, it is ended by pressing the dialog close box [X] on the caption. DIB is widely used in Windows so the script works on a lot of programs including Word. I first used this on screen shots. It also seems to work on Firefox, Chrome and Edge to right-click and copy images from webpages. One noticeable deficiency is that images that have transparent backgrounds will lose their transparency because DIB does not carry the transparent bit. In such images, the transparent areas turn black.


Well, this is a simple capture program. It can be easily expanded to provide for user entry of path and base filename, skipping existing files and event adding a ‘Pause’ button to the dialog. See what you can do to make a better widget.


 


Scott Theis is the President of Novaworks and the principal developer of the Legato scripting language. He has extensive expertise with EDGAR, HTML, XBRL, and other programming languages.

Additional Resources

Novaworks’ Legato Resources

Legato Script Developers LinkedIn Group

Primer: An Introduction to Legato 



Posted by
The Novaworks Team
in Development at 10:54
Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)
No comments
The author does not allow comments to this entry

Quicksearch

Categories

  • XML Accounting
  • XML AICPA News
  • XML FASB News
  • XML GASB News
  • XML IASB News
  • XML Development
  • XML Events
  • XML FERC
  • XML eForms News
  • XML FERC Filing Help
  • XML Filing Technology
  • XML Information Technology
  • XML Investor Education
  • XML MSRB
  • XML EMMA News
  • XML FDTA
  • XML MSRB Filing Help
  • XML Novaworks News
  • XML GoFiler Online Updates
  • XML GoFiler Updates
  • XML XBRLworks Updates
  • XML SEC
  • XML Corporation Finance
  • XML DERA
  • XML EDGAR News
  • XML Investment Management
  • XML SEC Filing Help
  • XML XBRL
  • XML Data Quality Committee
  • XML GRIP Taxonomy
  • XML IFRS Taxonomy
  • XML US GAAP Taxonomy

Calendar

Back May '25 Forward
Mo Tu We Th Fr Sa Su
Monday, May 19. 2025
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Feeds

  • XML
Sign Up Now
Get SEC news articles and blog posts delivered monthly to your inbox!
Based on the s9y Bulletproof template framework

Compliance

  • FERC
  • EDGAR
  • EMMA

Software

  • GoFiler Suite
  • SEC Exhibit Explorer
  • SEC Extractor
  • XBRLworks
  • Legato Scripting

Company

  • About Novaworks
  • News
  • Site Map
  • Support

Follow Us:

  • LinkedIn
  • YouTube
  • RSS
  • Newsletter
  • © 2024 Novaworks, LLC
  • Privacy
  • Terms of Use
  • Trademarks and Patents
  • Contact Us