function imageData = screencapture(varargin) % screencapture - get a screen-capture of a figure frame, component handle, or screen area rectangle % % ScreenCapture gets a screen-capture of any Matlab GUI handle (including desktop, % figure, axes, image or uicontrol), or a specified area rectangle located relative to % the specified handle. Screen area capture is possible by specifying the root (desktop) % handle (=0). The output can be either to an image file or to a Matlab matrix (useful % for displaying via imshow() or for further processing) or to the system clipboard. % This utility also enables adding a toolbar button for easy interactive screen-capture. % % Syntax: % imageData = screencapture(handle, position, target, 'PropName',PropValue, ...) % % Input Parameters: % handle - optional handle to be used for screen-capture origin. % If empty/unsupplied then current figure (gcf) will be used. % position - optional position array in pixels: [x,y,width,height]. % If empty/unsupplied then the handle's position vector will be used. % If both handle and position are empty/unsupplied then the position % will be retrieved via interactive mouse-selection. % If handle is an image, then position is in data (not pixel) units, so the % captured region remains the same after figure/axes resize (like imcrop) % target - optional filename for storing the screen-capture, or the % 'clipboard'/'printer' strings. % If empty/unsupplied then no output to file will be done. % The file format will be determined from the extension (JPG/PNG/...). % Supported formats are those supported by the imwrite function. % 'PropName',PropValue - % optional list of property pairs (e.g., 'target','myImage.png','pos',[10,20,30,40],'handle',gca) % PropNames may be abbreviated and are case-insensitive. % PropNames may also be given in whichever order. % Supported PropNames are: % - 'handle' (default: gcf handle) % - 'position' (default: gcf position array) % - 'target' (default: '') % - 'toolbar' (figure handle; default: gcf) % this adds a screen-capture button to the figure's toolbar % If this parameter is specified, then no screen-capture % will take place and the returned imageData will be []. % % Output parameters: % imageData - image data in a format acceptable by the imshow function % If neither target nor imageData were specified, the user will be % asked to interactively specify the output file. % % Examples: % imageData = screencapture; % interactively select screen-capture rectangle % imageData = screencapture(hListbox); % capture image of a uicontrol % imageData = screencapture(0, [20,30,40,50]); % capture a small desktop region % imageData = screencapture(gcf,[20,30,40,50]); % capture a small figure region % imageData = screencapture(gca,[10,20,30,40]); % capture a small axes region % imshow(imageData); % display the captured image in a matlab figure % imwrite(imageData,'myImage.png'); % save the captured image to file % img = imread('cameraman.tif'); % hImg = imshow(img); % screencapture(hImg,[60,35,140,80]); % capture a region of an image % screencapture(gcf,[],'myFigure.jpg'); % capture the entire figure into file % screencapture(gcf,[],'clipboard'); % capture the entire figure into clipboard % screencapture(gcf,[],'printer'); % print the entire figure % screencapture('handle',gcf,'target','myFigure.jpg'); % same as previous, save to file % screencapture('handle',gcf,'target','clipboard'); % same as previous, copy to clipboard % screencapture('handle',gcf,'target','printer'); % same as previous, send to printer % screencapture('toolbar',gcf); % adds a screen-capture button to gcf's toolbar % screencapture('toolbar',[],'target','sc.bmp'); % same with default output filename % % Technical description: % http://UndocumentedMatlab.com/blog/screencapture-utility/ % % Bugs and suggestions: % Please send to Yair Altman (altmany at gmail dot com) % % See also: % imshow, imwrite, print % % Release history: % 1.17 2016-05-16: Fix annoying warning about JavaFrame property becoming obsolete someday (yes, we know...) % 1.16 2016-04-19: Fix for deployed application suggested by Dwight Bartholomew % 1.10 2014-11-25: Added the 'print' target % 1.9 2014-11-25: Fix for saving GIF files % 1.8 2014-11-16: Fixes for R2014b % 1.7 2014-04-28: Fixed bug when capturing interactive selection % 1.6 2014-04-22: Only enable image formats when saving to an unspecified file via uiputfile % 1.5 2013-04-18: Fixed bug in capture of non-square image; fixes for Win64 % 1.4 2013-01-27: Fixed capture of Desktop (root); enabled rbbox anywhere on desktop (not necesarily in a Matlab figure); enabled output to clipboard (based on Jiro Doke's imclipboard utility); edge-case fixes; added Java compatibility check % 1.3 2012-07-23: Capture current object (uicontrol/axes/figure) if w=h=0 (e.g., by clicking a single point); extra input args sanity checks; fix for docked windows and image axes; include axes labels & ticks by default when capturing axes; use data-units position vector when capturing images; many edge-case fixes % 1.2 2011-01-16: another performance boost (thanks to Jan Simon); some compatibility fixes for Matlab 6.5 (untested) % 1.1 2009-06-03: Handle missing output format; performance boost (thanks to Urs); fix minor root-handle bug; added toolbar button option % 1.0 2009-06-02: First version posted on MathWorks File Exchange % License to use and modify this code is granted freely to all interested, as long as the original author is % referenced and attributed as such. The original author maintains the right to be solely associated with this work. % Programmed and Copyright by Yair M. Altman: altmany(at)gmail.com % $Revision: 1.17 $ $Date: 2016/05/16 17:59:36 $ % Ensure that java awt is enabled... if ~usejava('awt') error('YMA:screencapture:NeedAwt','ScreenCapture requires Java to run.'); end % Ensure that our Java version supports the Robot class (requires JVM 1.3+) try robot = java.awt.Robot; %#ok catch uiwait(msgbox({['Your Matlab installation is so old that its Java engine (' version('-java') ... ') does not have a java.awt.Robot class. '], ' ', ... 'Without this class, taking a screen-capture is impossible.', ' ', ... 'So, either install JVM 1.3 or higher, or use a newer Matlab release.'}, ... 'ScreenCapture', 'warn')); if nargout, imageData = []; end return; end % Process optional arguments paramsStruct = processArgs(varargin{:}); % If toolbar button requested, add it and exit if ~isempty(paramsStruct.toolbar) % Add the toolbar button addToolbarButton(paramsStruct); % Return the figure to its pre-undocked state (when relevant) redockFigureIfRelevant(paramsStruct); % Exit immediately (do NOT take a screen-capture) if nargout, imageData = []; end return; end % Convert position from handle-relative to desktop Java-based pixels [paramsStruct, msgStr] = convertPos(paramsStruct); % Capture the requested screen rectangle using java.awt.Robot imgData = getScreenCaptureImageData(paramsStruct.position); % Return the figure to its pre-undocked state (when relevant) redockFigureIfRelevant(paramsStruct); % Save image data in file or clipboard, if specified if ~isempty(paramsStruct.target) if strcmpi(paramsStruct.target,'clipboard') if ~isempty(imgData) imclipboard(imgData); else msgbox('No image area selected - not copying image to clipboard','ScreenCapture','warn'); end elseif strncmpi(paramsStruct.target,'print',5) % 'print' or 'printer' if ~isempty(imgData) hNewFig = figure('visible','off'); imshow(imgData); print(hNewFig); delete(hNewFig); else msgbox('No image area selected - not printing screenshot','ScreenCapture','warn'); end else % real filename if ~isempty(imgData) imwrite(imgData,paramsStruct.target); else msgbox(['No image area selected - not saving image file ' paramsStruct.target],'ScreenCapture','warn'); end end end % Return image raster data to user, if requested if nargout imageData = imgData; % If neither output formats was specified (neither target nor output data) elseif isempty(paramsStruct.target) & ~isempty(imgData) %#ok ML6 % Ask the user to specify a file %error('YMA:screencapture:noOutput','No output specified for ScreenCapture: specify the output filename and/or output data'); %format = '*.*'; formats = imformats; for idx = 1 : numel(formats) ext = sprintf('*.%s;',formats(idx).ext{:}); format(idx,1:2) = {ext(1:end-1), formats(idx).description}; %#ok end [filename,pathname] = uiputfile(format,'Save screen capture as'); if ~isequal(filename,0) & ~isequal(pathname,0) %#ok Matlab6 compatibility try filename = fullfile(pathname,filename); imwrite(imgData,filename); catch % possibly a GIF file that requires indexed colors [imgData,map] = rgb2ind(imgData,256); imwrite(imgData,map,filename); end else % TODO - copy to clipboard end end % Display msgStr, if relevant if ~isempty(msgStr) uiwait(msgbox(msgStr,'ScreenCapture')); drawnow; pause(0.05); % time for the msgbox to disappear end return; % debug breakpoint %% Process optional arguments function paramsStruct = processArgs(varargin) % Get the properties in either direct or P-V format [regParams, pvPairs] = parseparams(varargin); % Now process the optional P-V params try % Initialize paramName = []; paramsStruct = []; paramsStruct.handle = []; paramsStruct.position = []; paramsStruct.target = ''; paramsStruct.toolbar = []; paramsStruct.wasDocked = 0; % no false available in ML6 paramsStruct.wasInteractive = 0; % no false available in ML6 % Parse the regular (non-named) params in recption order if ~isempty(regParams) & (isempty(regParams{1}) | ishandle(regParams{1}(1))) %#ok ML6 paramsStruct.handle = regParams{1}; regParams(1) = []; end if ~isempty(regParams) & isnumeric(regParams{1}) & (length(regParams{1}) == 4) %#ok ML6 paramsStruct.position = regParams{1}; regParams(1) = []; end if ~isempty(regParams) & ischar(regParams{1}) %#ok ML6 paramsStruct.target = regParams{1}; end % Parse the optional param PV pairs supportedArgs = {'handle','position','target','toolbar'}; while ~isempty(pvPairs) % Disregard empty propNames (may be due to users mis-interpretting the syntax help) while ~isempty(pvPairs) & isempty(pvPairs{1}) %#ok ML6 pvPairs(1) = []; end if isempty(pvPairs) break; end % Ensure basic format is valid paramName = ''; if ~ischar(pvPairs{1}) error('YMA:screencapture:invalidProperty','Invalid property passed to ScreenCapture'); elseif length(pvPairs) == 1 if isempty(paramsStruct.target) paramsStruct.target = pvPairs{1}; break; else error('YMA:screencapture:noPropertyValue',['No value specified for property ''' pvPairs{1} '''']); end end % Process parameter values paramName = pvPairs{1}; if strcmpi(paramName,'filename') % backward compatibility paramName = 'target'; end paramValue = pvPairs{2}; pvPairs(1:2) = []; idx = find(strncmpi(paramName,supportedArgs,length(paramName))); if ~isempty(idx) %paramsStruct.(lower(supportedArgs{idx(1)})) = paramValue; % incompatible with ML6 paramsStruct = setfield(paramsStruct, lower(supportedArgs{idx(1)}), paramValue); %#ok ML6 % If 'toolbar' param specified, then it cannot be left empty - use gcf if strncmpi(paramName,'toolbar',length(paramName)) & isempty(paramsStruct.toolbar) %#ok ML6 paramsStruct.toolbar = getCurrentFig; end elseif isempty(paramsStruct.target) paramsStruct.target = paramName; pvPairs = {paramValue, pvPairs{:}}; %#ok (more readable this way, although a bit less efficient...) else supportedArgsStr = sprintf('''%s'',',supportedArgs{:}); error('YMA:screencapture:invalidProperty','%s \n%s', ... 'Invalid property passed to ScreenCapture', ... ['Supported property names are: ' supportedArgsStr(1:end-1)]); end end % loop pvPairs catch if ~isempty(paramName), paramName = [' ''' paramName '''']; end error('YMA:screencapture:invalidProperty','Error setting ScreenCapture property %s:\n%s',paramName,lasterr); %#ok end %end % processArgs %% Convert position from handle-relative to desktop Java-based pixels function [paramsStruct, msgStr] = convertPos(paramsStruct) msgStr = ''; try % Get the screen-size for later use screenSize = get(0,'ScreenSize'); % Get the containing figure's handle hParent = paramsStruct.handle; if isempty(paramsStruct.handle) paramsStruct.hFigure = getCurrentFig; hParent = paramsStruct.hFigure; else paramsStruct.hFigure = ancestor(paramsStruct.handle,'figure'); end % To get the acurate pixel position, the figure window must be undocked try if strcmpi(get(paramsStruct.hFigure,'WindowStyle'),'docked') set(paramsStruct.hFigure,'WindowStyle','normal'); drawnow; pause(0.25); paramsStruct.wasDocked = 1; % no true available in ML6 end catch % never mind - ignore... end % The figure (if specified) must be in focus if ~isempty(paramsStruct.hFigure) & ishandle(paramsStruct.hFigure) %#ok ML6 isFigureValid = 1; % no true available in ML6 figure(paramsStruct.hFigure); else isFigureValid = 0; % no false available in ML6 end % Flush all graphic events to ensure correct rendering drawnow; pause(0.01); % No handle specified wasPositionGiven = 1; % no true available in ML6 if isempty(paramsStruct.handle) % Set default handle, if not supplied paramsStruct.handle = paramsStruct.hFigure; % If position was not specified, get it interactively using RBBOX if isempty(paramsStruct.position) [paramsStruct.position, jFrameUsed, msgStr] = getInteractivePosition(paramsStruct.hFigure); %#ok jFrameUsed is unused paramsStruct.wasInteractive = 1; % no true available in ML6 wasPositionGiven = 0; % no false available in ML6 end elseif ~ishandle(paramsStruct.handle) % Handle was supplied - ensure it is a valid handle error('YMA:screencapture:invalidHandle','Invalid handle passed to ScreenCapture'); elseif isempty(paramsStruct.position) % Handle was supplied but position was not, so use the handle's position paramsStruct.position = getPixelPos(paramsStruct.handle); paramsStruct.position(1:2) = 0; wasPositionGiven = 0; % no false available in ML6 elseif ~isnumeric(paramsStruct.position) | (length(paramsStruct.position) ~= 4) %#ok ML6 % Both handle & position were supplied - ensure a valid pixel position vector error('YMA:screencapture:invalidPosition','Invalid position vector passed to ScreenCapture: \nMust be a [x,y,w,h] numeric pixel array'); end % Capture current object (uicontrol/axes/figure) if w=h=0 (single-click in interactive mode) if paramsStruct.position(3)<=0 | paramsStruct.position(4)<=0 %#ok ML6 %TODO - find a way to single-click another Matlab figure (the following does not work) %paramsStruct.position = getPixelPos(ancestor(hittest,'figure')); paramsStruct.position = getPixelPos(paramsStruct.handle); paramsStruct.position(1:2) = 0; paramsStruct.wasInteractive = 0; % no false available in ML6 wasPositionGiven = 0; % no false available in ML6 end % First get the parent handle's desktop-based Matlab pixel position parentPos = [0,0,0,0]; dX = 0; dY = 0; dW = 0; dH = 0; if ~isFigure(hParent) % Get the reguested component's pixel position parentPos = getPixelPos(hParent, 1); % no true available in ML6 % Axes position inaccuracy estimation deltaX = 3; deltaY = -1; % Fix for images if isImage(hParent) % | (isAxes(hParent) & strcmpi(get(hParent,'YDir'),'reverse')) %#ok ML6 % Compensate for resized image axes hAxes = get(hParent,'Parent'); if all(get(hAxes,'DataAspectRatio')==1) % sanity check: this is the normal behavior % Note 18/4/2013: the following fails for non-square images %actualImgSize = min(parentPos(3:4)); %dX = (parentPos(3) - actualImgSize) / 2; %dY = (parentPos(4) - actualImgSize) / 2; %parentPos(3:4) = actualImgSize; % The following should work for all types of images actualImgSize = size(get(hParent,'CData')); dX = (parentPos(3) - min(parentPos(3),actualImgSize(2))) / 2; dY = (parentPos(4) - min(parentPos(4),actualImgSize(1))) / 2; parentPos(3:4) = actualImgSize([2,1]); %parentPos(3) = max(parentPos(3),actualImgSize(2)); %parentPos(4) = max(parentPos(4),actualImgSize(1)); end % Fix user-specified img positions (but not auto-inferred ones) if wasPositionGiven % In images, use data units rather than pixel units % Reverse the YDir ymax = max(get(hParent,'YData')); paramsStruct.position(2) = ymax - paramsStruct.position(2) - paramsStruct.position(4); % Note: it would be best to use hgconvertunits, but: % ^^^^ (1) it fails on Matlab 6, and (2) it doesn't accept Data units %paramsStruct.position = hgconvertunits(hFig, paramsStruct.position, 'Data', 'pixel', hParent); % fails! xLims = get(hParent,'XData'); yLims = get(hParent,'YData'); xPixelsPerData = parentPos(3) / (diff(xLims) + 1); yPixelsPerData = parentPos(4) / (diff(yLims) + 1); paramsStruct.position(1) = round((paramsStruct.position(1)-xLims(1)) * xPixelsPerData); paramsStruct.position(2) = round((paramsStruct.position(2)-yLims(1)) * yPixelsPerData + 2*dY); paramsStruct.position(3) = round( paramsStruct.position(3) * xPixelsPerData); paramsStruct.position(4) = round( paramsStruct.position(4) * yPixelsPerData); % Axes position inaccuracy estimation if strcmpi(computer('arch'),'win64') deltaX = 7; deltaY = -7; else deltaX = 3; deltaY = -3; end else % axes/image position was auto-infered (entire image) % Axes position inaccuracy estimation if strcmpi(computer('arch'),'win64') deltaX = 6; deltaY = -6; else deltaX = 2; deltaY = -2; end dW = -2*dX; dH = -2*dY; end end %hFig = ancestor(hParent,'figure'); hParent = paramsStruct.hFigure; elseif paramsStruct.wasInteractive % interactive figure rectangle % Compensate for 1px rbbox inaccuracies deltaX = 2; deltaY = -2; else % non-interactive figure % Compensate 4px figure boundaries = difference betweeen OuterPosition and Position deltaX = -1; deltaY = 1; end %disp(paramsStruct.position) % for debugging % Now get the pixel position relative to the monitor figurePos = getPixelPos(hParent); desktopPos = figurePos + parentPos; % Now convert to Java-based pixels based on screen size % Note: multiple monitors are automatically handled correctly, since all % ^^^^ Java positions are relative to the main monitor's top-left corner javaX = desktopPos(1) + paramsStruct.position(1) + deltaX + dX; javaY = screenSize(4) - desktopPos(2) - paramsStruct.position(2) - paramsStruct.position(4) + deltaY + dY; width = paramsStruct.position(3) + dW; height = paramsStruct.position(4) + dH; paramsStruct.position = round([javaX, javaY, width, height]); %paramsStruct.position % Ensure the figure is at the front so it can be screen-captured if isFigureValid figure(hParent); drawnow; pause(0.02); end catch % Maybe root/desktop handle (root does not have a 'Position' prop so getPixelPos croaks if isequal(double(hParent),0) % =root/desktop handle; handles case of hParent=[] javaX = paramsStruct.position(1) - 1; javaY = screenSize(4) - paramsStruct.position(2) - paramsStruct.position(4) - 1; paramsStruct.position = [javaX, javaY, paramsStruct.position(3:4)]; end end %end % convertPos %% Interactively get the requested capture rectangle function [positionRect, jFrameUsed, msgStr] = getInteractivePosition(hFig) msgStr = ''; try % First try the invisible-figure approach, in order to % enable rbbox outside any existing figure boundaries f = figure('units','pixel','pos',[-100,-100,10,10],'HitTest','off'); drawnow; pause(0.01); oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame'); jf = get(handle(f),'JavaFrame'); warning(oldWarn); try jWindow = jf.fFigureClient.getWindow; catch try jWindow = jf.fHG1Client.getWindow; catch jWindow = jf.getFigurePanelContainer.getParent.getTopLevelAncestor; end end com.sun.awt.AWTUtilities.setWindowOpacity(jWindow,0.05); %=nearly transparent (not fully so that mouse clicks are captured) jWindow.setMaximized(1); % no true available in ML6 jFrameUsed = 1; % no true available in ML6 msg = {'Mouse-click and drag a bounding rectangle for screen-capture ' ... ... %'or single-click any Matlab figure to capture the entire figure.' ... }; catch % Something failed, so revert to a simple rbbox on a visible figure try delete(f); drawnow; catch, end %Cleanup... jFrameUsed = 0; % no false available in ML6 msg = {'Mouse-click within any Matlab figure and then', ... 'drag a bounding rectangle for screen-capture,', ... 'or single-click to capture the entire figure'}; end uiwait(msgbox(msg,'ScreenCapture')); k = waitforbuttonpress; %#ok k is unused %hFig = getCurrentFig; %p1 = get(hFig,'CurrentPoint'); positionRect = rbbox; %p2 = get(hFig,'CurrentPoint'); if jFrameUsed jFrameOrigin = getPixelPos(f); delete(f); drawnow; try figOrigin = getPixelPos(hFig); catch % empty/invalid hFig handle figOrigin = [0,0,0,0]; end else if isempty(hFig) jFrameOrigin = getPixelPos(gcf); else jFrameOrigin = [0,0,0,0]; end figOrigin = [0,0,0,0]; end positionRect(1:2) = positionRect(1:2) + jFrameOrigin(1:2) - figOrigin(1:2); if prod(positionRect(3:4)) > 0 msgStr = sprintf('%dx%d area captured',positionRect(3),positionRect(4)); end %end % getInteractivePosition %% Get current figure (even if its handle is hidden) function hFig = getCurrentFig oldState = get(0,'showHiddenHandles'); set(0,'showHiddenHandles','on'); hFig = get(0,'CurrentFigure'); set(0,'showHiddenHandles',oldState); %end % getCurrentFig %% Get ancestor figure - used for old Matlab versions that don't have a built-in ancestor() function hObj = ancestor(hObj,type) if ~isempty(hObj) & ishandle(hObj) %#ok for Matlab 6 compatibility try hObj = get(hObj,'Ancestor'); catch % never mind... end try %if ~isa(handle(hObj),type) % this is best but always returns 0 in Matlab 6! %if ~isprop(hObj,'type') | ~strcmpi(get(hObj,'type'),type) % no isprop() in ML6! try objType = get(hObj,'type'); catch objType = ''; end if ~strcmpi(objType,type) try parent = get(handle(hObj),'parent'); catch parent = hObj.getParent; % some objs have no 'Parent' prop, just this method... end if ~isempty(parent) % empty parent means root ancestor, so exit hObj = ancestor(parent,type); end end catch % never mind... end end %end % ancestor %% Get position of an HG object in specified units function pos = getPos(hObj,field,units) % Matlab 6 did not have hgconvertunits so use the old way... oldUnits = get(hObj,'units'); if strcmpi(oldUnits,units) % don't modify units unless we must! pos = get(hObj,field); else set(hObj,'units',units); pos = get(hObj,field); set(hObj,'units',oldUnits); end %end % getPos %% Get pixel position of an HG object - for Matlab 6 compatibility function pos = getPixelPos(hObj,varargin) persistent originalObj try stk = dbstack; if ~strcmp(stk(2).name,'getPixelPos') originalObj = hObj; end if isFigure(hObj) %| isAxes(hObj) %try pos = getPos(hObj,'OuterPosition','pixels'); else %catch % getpixelposition is unvectorized unfortunately! pos = getpixelposition(hObj,varargin{:}); % add the axes labels/ticks if relevant (plus a tiny margin to fix 2px label/title inconsistencies) if isAxes(hObj) & ~isImage(originalObj) %#ok ML6 tightInsets = getPos(hObj,'TightInset','pixel'); pos = pos + tightInsets.*[-1,-1,1,1] + [-1,1,1+tightInsets(1:2)]; end end catch try % Matlab 6 did not have getpixelposition nor hgconvertunits so use the old way... pos = getPos(hObj,'Position','pixels'); catch % Maybe the handle does not have a 'Position' prop (e.g., text/line/plot) - use its parent pos = getPixelPos(get(hObj,'parent'),varargin{:}); end end % Handle the case of missing/invalid/empty HG handle if isempty(pos) pos = [0,0,0,0]; end %end % getPixelPos %% Adds a ScreenCapture toolbar button function addToolbarButton(paramsStruct) % Ensure we have a valid toolbar handle hFig = ancestor(paramsStruct.toolbar,'figure'); if isempty(hFig) error('YMA:screencapture:badToolbar','the ''Toolbar'' parameter must contain a valid GUI handle'); end set(hFig,'ToolBar','figure'); hToolbar = findall(hFig,'type','uitoolbar'); if isempty(hToolbar) error('YMA:screencapture:noToolbar','the ''Toolbar'' parameter must contain a figure handle possessing a valid toolbar'); end hToolbar = hToolbar(1); % just in case there are several toolbars... - use only the first % Prepare the camera icon icon = ['3333333333333333'; ... '3333333333333333'; ... '3333300000333333'; ... '3333065556033333'; ... '3000000000000033'; ... '3022222222222033'; ... '3022220002222033'; ... '3022203110222033'; ... '3022201110222033'; ... '3022204440222033'; ... '3022220002222033'; ... '3022222222222033'; ... '3000000000000033'; ... '3333333333333333'; ... '3333333333333333'; ... '3333333333333333']; cm = [ 0 0 0; ... % black 0 0.60 1; ... % light blue 0.53 0.53 0.53; ... % light gray NaN NaN NaN; ... % transparent 0 0.73 0; ... % light green 0.27 0.27 0.27; ... % gray 0.13 0.13 0.13]; % dark gray cdata = ind2rgb(uint8(icon-'0'),cm); % If the button does not already exit hButton = findall(hToolbar,'Tag','ScreenCaptureButton'); tooltip = 'Screen capture'; if ~isempty(paramsStruct.target) tooltip = [tooltip ' to ' paramsStruct.target]; end if isempty(hButton) % Add the button with the icon to the figure's toolbar hButton = uipushtool(hToolbar, 'CData',cdata, 'Tag','ScreenCaptureButton', 'TooltipString',tooltip, 'ClickedCallback',['screencapture(''' paramsStruct.target ''')']); %#ok unused else % Otherwise, simply update the existing button set(hButton, 'CData',cdata, 'Tag','ScreenCaptureButton', 'TooltipString',tooltip, 'ClickedCallback',['screencapture(''' paramsStruct.target ''')']); end %end % addToolbarButton %% Java-get the actual screen-capture image data function imgData = getScreenCaptureImageData(positionRect) if isempty(positionRect) | all(positionRect==0) | positionRect(3)<=0 | positionRect(4)<=0 %#ok ML6 imgData = []; else % Use java.awt.Robot to take a screen-capture of the specified screen area rect = java.awt.Rectangle(positionRect(1), positionRect(2), positionRect(3), positionRect(4)); robot = java.awt.Robot; jImage = robot.createScreenCapture(rect); % Convert the resulting Java image to a Matlab image % Adapted for a much-improved performance from: % http://www.mathworks.com/support/solutions/data/1-2WPAYR.html h = jImage.getHeight; w = jImage.getWidth; %imgData = zeros([h,w,3],'uint8'); %pixelsData = uint8(jImage.getData.getPixels(0,0,w,h,[])); %for i = 1 : h % base = (i-1)*w*3+1; % imgData(i,1:w,:) = deal(reshape(pixelsData(base:(base+3*w-1)),3,w)'); %end % Performance further improved based on feedback from Urs Schwartz: %pixelsData = reshape(typecast(jImage.getData.getDataStorage,'uint32'),w,h).'; %imgData(:,:,3) = bitshift(bitand(pixelsData,256^1-1),-8*0); %imgData(:,:,2) = bitshift(bitand(pixelsData,256^2-1),-8*1); %imgData(:,:,1) = bitshift(bitand(pixelsData,256^3-1),-8*2); % Performance even further improved based on feedback from Jan Simon: pixelsData = reshape(typecast(jImage.getData.getDataStorage, 'uint8'), 4, w, h); imgData = cat(3, ... transpose(reshape(pixelsData(3, :, :), w, h)), ... transpose(reshape(pixelsData(2, :, :), w, h)), ... transpose(reshape(pixelsData(1, :, :), w, h))); end %end % getInteractivePosition %% Return the figure to its pre-undocked state (when relevant) function redockFigureIfRelevant(paramsStruct) if paramsStruct.wasDocked try set(paramsStruct.hFigure,'WindowStyle','docked'); %drawnow; catch % never mind - ignore... end end %end % redockFigureIfRelevant %% Copy screen-capture to the system clipboard % Adapted from http://www.mathworks.com/matlabcentral/fileexchange/28708-imclipboard/content/imclipboard.m function imclipboard(imgData) % Import necessary Java classes import java.awt.Toolkit.* import java.awt.image.BufferedImage import java.awt.datatransfer.DataFlavor % Add the necessary Java class (ImageSelection) to the Java classpath if ~exist('ImageSelection', 'class') % Obtain the directory of the executable (or of the M-file if not deployed) %javaaddpath(fileparts(which(mfilename)), '-end'); if isdeployed % Stand-alone mode. [status, result] = system('path'); %#ok MatLabFilePath = char(regexpi(result, 'Path=(.*?);', 'tokens', 'once')); else % MATLAB mode. MatLabFilePath = fileparts(mfilename('fullpath')); end javaaddpath(MatLabFilePath, '-end'); end % Get System Clipboard object (java.awt.Toolkit) cb = getDefaultToolkit.getSystemClipboard; % can't use () in ML6! % Get image size ht = size(imgData, 1); wd = size(imgData, 2); % Convert to Blue-Green-Red format imgData = imgData(:, :, [3 2 1]); % Convert to 3xWxH format imgData = permute(imgData, [3, 2, 1]); % Append Alpha data (not used) imgData = cat(1, imgData, 255*ones(1, wd, ht, 'uint8')); % Create image buffer imBuffer = BufferedImage(wd, ht, BufferedImage.TYPE_INT_RGB); imBuffer.setRGB(0, 0, wd, ht, typecast(imgData(:), 'int32'), 0, wd); % Create ImageSelection object % % custom java class imSelection = ImageSelection(imBuffer); % Set clipboard content to the image cb.setContents(imSelection, []); %end %imclipboard %% Is the provided handle a figure? function flag = isFigure(hObj) flag = isa(handle(hObj),'figure') | isa(hObj,'matlab.ui.Figure'); %end %isFigure %% Is the provided handle an axes? function flag = isAxes(hObj) flag = isa(handle(hObj),'axes') | isa(hObj,'matlab.graphics.axis.Axes'); %end %isFigure %% Is the provided handle an image? function flag = isImage(hObj) flag = isa(handle(hObj),'image') | isa(hObj,'matlab.graphics.primitive.Image'); %end %isFigure %%%%%%%%%%%%%%%%%%%%%%%%%% TODO %%%%%%%%%%%%%%%%%%%%%%%%% % find a way in interactive-mode to single-click another Matlab figure for screen-capture