Remove whitespace around exported (saved) figure via imwrite

54 views (last 30 days)
John Cruce
John Cruce on 28 Sep 2021
Edited: DGM on 29 Sep 2021
I'm trying to save a figure using getframe and imwrite, however, there's a lot of whitespace around the figure I'd like to remove. Basically I want the saved png tight around the title, figure, and colorbar. Any thoughts on how I might do this? My code is below.
% Open figure
set(gca,'xtick',[],'xticklabel',[],'ytick',[],'yticklabel',[],'color','w');
set(gcf,'units','pixel','position',[0,10,650,650],'color','w');
m_proj('Miller Cylindrical','lon',[-92.5 -87.5],'lat',[27.5 32]);
m_grid('xtick',[],'ytick',[],'linestyle','none','backgroundcolor',[0 0 0]);
ax=gca;
colormap(jet(50));
% Set the scale of the colormap for the contours
caxis([0, 50]);
hcb=colorbar('SouthOutside');
hcb.Label.String='Color Bar Label';
axPos = ax.Position;
colorbarpos=hcb.Position;
% Position for SouthOutside colorbar
colorbarpos(2)=0.032+colorbarpos(2);
colorbarpos(4)=0.5*colorbarpos(4);
hcb.Position = colorbarpos;
ax.Position = axPos;
set(hcb,'YTick',[0:1:50],'TickLength',colorbarpos(4)/colorbarpos(3));
set(hcb,'YTickLabel',{'';'1';'';'';'';'5';'';'';'';'';'10';'';'';'';'';'15';'';'';'';'';'20';'';'';'';'';'25';'';'';'';'';'30';'';'';'';'';'35';'';'';'';'';'40';'';'';'';'';'45';'';'';'';'';'50';});
t = title({['\fontsize{12}','Test Plot']},'FontWeight','Bold');
f=getframe(gcf);
imwrite(f.cdata,'test.png','png');

Accepted Answer

Dave B
Dave B on 29 Sep 2021
Edited: Dave B on 29 Sep 2021
If/when you upgrade to R2020a+ consider trying exportgraphics(gca, ...) which trims images nice and tight and may be easier than working with imwrite.
In the mean time...you could crop f.cdata based on the rows/columns that are all white (because your figure background is white).
% Open figure
set(gca,'xtick',[],'xticklabel',[],'ytick',[],'yticklabel',[],'color','w');
set(gcf,'units','pixel','position',[0,10,650,650],'color','w');
imagesc(magic(10)) % I didn't have m_proj so I used image as a placeholder
ax=gca;
colormap(jet(50));
% Set the scale of the colormap for the contours
caxis([0, 50]);
hcb=colorbar('SouthOutside');
hcb.Label.String='Color Bar Label';
axPos = ax.Position;
colorbarpos=hcb.Position;
% Position for SouthOutside colorbar
colorbarpos(2)=0.032+colorbarpos(2);
colorbarpos(4)=0.5*colorbarpos(4);
hcb.Position = colorbarpos;
ax.Position = axPos;
set(hcb,'YTick',[0:1:50],'TickLength',colorbarpos(4)/colorbarpos(3));
set(hcb,'YTickLabel',{'';'1';'';'';'';'5';'';'';'';'';'10';'';'';'';'';'15';'';'';'';'';'20';'';'';'';'';'25';'';'';'';'';'30';'';'';'';'';'35';'';'';'';'';'40';'';'';'';'';'45';'';'';'';'';'50';});
t = title({['\fontsize{12}','Test Plot']},'FontWeight','Bold');
f=getframe(gcf);
iswhite=min(f.cdata,[],3)==255;
blankcols=all(iswhite,1);
col_ind = find(~blankcols,1,'first'):find(~blankcols,1,'last');
blankrows=all(iswhite,2);
row_ind = find(~blankrows,1,'first'):find(~blankrows,1,'last');
cropdata = f.cdata(row_ind,col_ind,:);
% demo of pre/post trim (for ML answers, can remove for export)
figure
tiledlayout(1,2,'Padding','none','TileSpacing','tight')
image(nexttile,f.cdata); axis image;xticks([]);yticks([])
image(nexttile,cropdata);axis image;xticks([]);yticks([])
% uncomment this to write the image
% imwrite(cropdata,'test.png','png');
Exported image

More Answers (1)

DGM
DGM on 29 Sep 2021
Edited: DGM on 29 Sep 2021
Is there any reason you're not using print(), saveas(), or exportgraphics()?
Instead of
f=getframe(gcf);
imwrite(f.cdata,'test.png','png');
you could try
saveas(gcf,'testsaveas.png');
or maybe
print('testprint','-dpng');
or exportgraphics(), which I don't have (I guess you don't either).
If none of that changes the padding sufficiently, or if you need to process existing saved figures, you'll have to crop the images. You could use imcrop() if you could determine the correct rect parameter, but that's going to be a pain. MIMT has cropborder(), which has optional automatic cropping modes specifically for tasks like this:
% Open figure
set(gca,'xtick',[],'xticklabel',[],'ytick',[],'yticklabel',[],'color','w');
set(gcf,'units','pixel','position',[0,10,650,650],'color','w');
h = surf(3.2*peaks+23); h.EdgeAlpha = 0.1;
ax=gca;
colormap(jet(50));
% Set the scale of the colormap for the contours
caxis([0, 50]);
hcb=colorbar('SouthOutside');
hcb.Label.String='Color Bar Label';
axPos = ax.Position;
colorbarpos=hcb.Position;
% Position for SouthOutside colorbar
colorbarpos(2)=0.032+colorbarpos(2);
colorbarpos(4)=0.5*colorbarpos(4);
hcb.Position = colorbarpos;
ax.Position = axPos;
set(hcb,'YTick',[0:1:50],'TickLength',colorbarpos(4)/colorbarpos(3));
set(hcb,'YTickLabel',{'';'1';'';'';'';'5';'';'';'';'';'10';'';'';'';'';'15';'';'';'';'';'20';'';'';'';'';'25';'';'';'';'';'30';'';'';'';'';'35';'';'';'';'';'40';'';'';'';'';'45';'';'';'';'';'50';});
t = title({['\fontsize{12}','Test Plot']},'FontWeight','Bold');
f = getframe(gcf);
f = cropborder(f.cdata,[NaN NaN NaN NaN],'threshold',0.0001);
f = addborder(f,10,[1 0 0],'normalized'); % for web demo only!
imwrite(f,'test.png','png');
imshow(f)
In this example, I added a red border so that you can see where the image boundary is against the white website background. You obviously don't need to add a red border to anything.
As mentioned, cropborder() is from MIMT on the FEX:
Cropborder webdocs are here:

Products


Release

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!