【问题标题】:Bitmap-render part of plot during vector-graphics export in MATLAB在 MATLAB 中导出矢量图形期间的位图渲染部分
【发布时间】:2017-05-31 13:55:40
【问题描述】:

我有一个相当复杂的函数,我使用fsurf 绘制了一个相当高的MeshDensity(我不能低于默认值,即 35)。导出这个数字 (saveas(gcf, 'file.pdf', 'pdf');) 会生成一个 20 MB 左右的质量非常好的 pdf 文件,但渲染速度非常慢。我想减少文件大小,最重要的是,减少这个 pdf 文件的复杂性,而不是将整个图(我的意思是整个 MATLAB 图)导出为位图。我该怎么做?

完美的答案将解释我如何将表面图(我的意思是白色背景上的彩色函数表面)转换为位图,同时保持轴和标签的矢量化特性。

更新:以下是此类情节的示例。

【问题讨论】:

  • “我想要一个矢量和一个位图,同时”。嗯嗯嗯。
  • @AnderBiguri 在我的世界里,这被称为“嵌入”,对于曾经在 pdf 文件中看过照片的人来说,这并不是一个很大的困惑。
  • pdf 文件中的照片只是位图,没有矢量图形。展示你的形象,有可能,只是可能
  • @AnderBiguri 好吧,标准文本,除非呈现为位图,也非常接近我认为的矢量图形。所以我应该说,“任何曾经在pdf文件中在某些文本旁边看过照片的人”?无论如何,我相信你明白我的意思。我会用一些快照更新问题。
  • 无意冒犯,但我不明白你的意思。你不能“考虑”一些矢量图形。矢量图形是一种存储信息的方式,而不是视觉外观。某些东西是或不是矢量图形。您可以将位图放入 PDF 中,没有任何问题。我不认为你可以制作一个既是位图(用于冲浪)又是矢量(用于轴)的图形。我认为没有任何文件格式允许这样做。

标签: matlab graphics vector-graphics bitmapimage


【解决方案1】:

这是我的函数 BitmapRender,它对图形的一部分进行 Bitmap 渲染:

%% Test Code
clc;clf;
Objects = surf(-4-2*peaks);
hold('on');
Objects(2 : 50) = plot(peaks);
Objects(51) = imagesc([20 40], [0, 5], magic(100));
hold('off');
ylim([0 10]);
zlim([-10 15]);
Objects(1).Parent.GridLineStyle = 'none';
view(45, 45);
set(gcf, 'Color', 'white');
rotate3d on

saveas(gcf, 'pre.pdf');
BitmapRender(gca, Objects(2 : 3 : end));
% BitmapRender(gca, Objects(2 : 3 : end), [0.25 0.25 0.5 0.5], false);
saveas(gcf, 'post.pdf');

函数本身非常简单,除了(重新)处理可见性,因为按下空格键(在旋转、缩放等之后)重新渲染图形。

function BitmapRender(Axes, KeepObjects, RelativePosition, Draft, Key)

if nargin < 2
    KeepObjects = [];
end
if nargin < 3
    RelativePosition = [0 0 1 1];
end
if nargin < 4
    Draft = false;
end
if nargin < 5
    Key = '';
end

Figure = Axes.Parent;
FigureInnerWH = Figure.InnerPosition([3 4 3 4]);
PixelPosition = round(RelativePosition .* FigureInnerWH);

if isempty(Key)
    OverlayAxes = axes(Figure, 'Units', 'Normalized', 'Position', PixelPosition ./ FigureInnerWH);
    if Draft
        OverlayAxes.Box = 'on';
        OverlayAxes.Color = 'none';
        OverlayAxes.XTick = [];
        OverlayAxes.YTick = [];
        OverlayAxes.HitTest = 'off';
    else
        uistack(OverlayAxes, 'bottom');
        OverlayAxes.Visible = 'off';
    end
    setappdata(Figure, 'BitmapRenderOriginalVisibility', get(Axes.Children, 'Visible'));

    Axes.CLimMode = 'manual';
    Axes.XLimMode = 'manual';
    Axes.YLimMode = 'manual';
    Axes.ZLimMode = 'manual';

    hManager = uigetmodemanager(Figure);
    [hManager.WindowListenerHandles.Enabled] = deal(false);
    set(Figure, 'KeyPressFcn', @(f, e) BitmapRender(gca, KeepObjects, RelativePosition, Draft, e.Key));
elseif strcmpi(Key, 'space')
    OverlayAxes = findobj(Figure, 'Tag', 'BitmapRenderOverlayAxes');
    delete(get(OverlayAxes, 'Children'));
    OriginalVisibility = getappdata(Figure, 'BitmapRenderOriginalVisibility');
    [Axes.Children.Visible] = deal(OriginalVisibility{:});
else
    return;
end

if Draft
    return;
end

Axes.Visible = 'off';

KeepObjectsVisibility = get(KeepObjects, 'Visible');
[KeepObjects.Visible] = deal('off');

drawnow;
Frame = getframe(Figure, PixelPosition);

[Axes.Children.Visible] = deal('off');
Axes.Visible = 'on';
Axes.Color = 'none';
if numel(KeepObjects) == 1
    KeepObjects.Visible = KeepObjectsVisibility;
else
    [KeepObjects.Visible] = deal(KeepObjectsVisibility{:});
end

Image = imagesc(OverlayAxes, Frame.cdata);
uistack(Image, 'bottom');
OverlayAxes.Tag = 'BitmapRenderOverlayAxes';
OverlayAxes.Visible = 'off';

end

显然,就屏幕像素而言,该解决方案是像素完美的。两个 pdf 文件(pre 和 post)看起来像这样。请注意,表面、图像和一些绘图线是位图渲染的,但其他一些绘图线以及轴和标签仍然是矢量化的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多