这个问题困扰我好几年了:
幕布自身并不支持表格。每次需要表格,我都是先用Word编辑好,再以图片的形式粘贴到幕布中。
步骤十分繁琐:
在Word中选中 > 复制 > 粘贴为图片 > 再次剪切图片 > 在幕布中粘贴
那么有没有Office插件能直接把Word选定的内容复制为图片呢?
像Excel的自带功能这样
这个问题困扰我好几年了:
幕布自身并不支持表格。每次需要表格,我都是先用Word编辑好,再以图片的形式粘贴到幕布中。
步骤十分繁琐:
在Word中选中 > 复制 > 粘贴为图片 > 再次剪切图片 > 在幕布中粘贴
那么有没有Office插件能直接把Word选定的内容复制为图片呢?
像Excel的自带功能这样
新建一个宏,录制动作就好了.如果运行出错,编辑宏,把picture n的这一行注释掉.
参考代码
Sub copy2img()
’
’ copy2img
’ office复制内容为图片 宏
’ 快捷键: Ctrl+m
’
Selection.Copy
ActiveSheet.Pictures.Paste.Select
’ ActiveSheet.Shapes.Range(Array(“Picture 6”)).Select
Application.CutCopyMode = False
Selection.Cut
End Sub
我终于懂了 OneNote 里复制为图片是干什么用的了…
OneNote也没有复制为图片的选项呀
试了下,注不注释都不能运行
重新录了一个。倒是可以一键执行了,不过由于并没有实质上避开“粘贴为图片”的操作,执行时屏幕会闪一下,偶尔边距还会出现奇怪的空白
Sub 复制为图片()
'
' 复制为图片 宏
'
'
Selection.Copy
Selection.MoveRight Unit:=wdCharacter, Count:=1
Selection.TypeParagraph
Selection.PasteSpecial Link:=False, DataType:=wdPasteEnhancedMetafile, _
Placement:=wdInLine, DisplayAsIcon:=False
Selection.MoveLeft Unit:=wdCharacter, Count:=2, Extend:=wdExtend
Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend
Selection.Cut
End Sub
啊,那为什么我复制的就是图片呢
点那个框框复制就行
可能版本不一样?反正就那么回事,录制一下,如果哪个步骤录制的和期望不一样,手动再改下就完事。office的宏还是蛮好用的,只是有的公司处于安全考虑,会禁止使用宏。
office内容复制后一般有EMF格式的剪贴板数据。
可以使用代码读取后,转换为位图格式,再写回剪贴板,然后就可以在别的地方粘贴了。
粘贴结果:
Quicker动作:
主要代码:
//.cs 文件类型,便于外部编辑时使用
// 引用必要的命名空间
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
public class ClipboardFunctions
{
[DllImport("user32.dll", EntryPoint = "OpenClipboard", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenClipboard(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "EmptyClipboard", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EmptyClipboard();
[DllImport("user32.dll", EntryPoint = "SetClipboardData", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr SetClipboardData(int uFormat, IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "CloseClipboard", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CloseClipboard();
[DllImport("user32.dll", EntryPoint = "GetClipboardData", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr GetClipboardData(int uFormat);
[DllImport("user32.dll", EntryPoint = "IsClipboardFormatAvailable", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern short IsClipboardFormatAvailable(int uFormat);
}
// Quicker将会调用的函数
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 读取动作里的变量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "从脚本输出的内容。"); // 向变量里输出值
//MessageBox.Show("Hello World!");
const int CF_ETAFILE = 14;
IntPtr intptr;
System.Drawing.Imaging.Metafile myMetaFile = null;
if (ClipboardFunctions.OpenClipboard(IntPtr.Zero))
{
if (ClipboardFunctions.IsClipboardFormatAvailable(CF_ETAFILE) != 0)
{
intptr = ClipboardFunctions.GetClipboardData(CF_ETAFILE);
myMetaFile = new System.Drawing.Imaging.Metafile(intptr, true);
ClipboardFunctions.CloseClipboard();
using(MemoryStream stream = new MemoryStream())
{
myMetaFile.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
var bitmap = Image.FromStream(stream);
//Clipboard.SetImage(bitmap);
SetClipboardImage((Bitmap)bitmap, null,null);
return;
}
}
}
throw new Exception("剪贴板中没有EMF图片信息,请从Office中复制内容后重试。");
}
/// <summary>
/// Copies the given image to the clipboard as PNG, DIB and standard Bitmap format.
/// </summary>
/// <param name="image">Image to put on the clipboard.</param>
/// <param name="imageNoTr">Optional specifically nontransparent version of the image to put on the clipboard.</param>
/// <param name="data">Clipboard data object to put the image into. Might already contain other stuff. Leave null to create a new one.</param>
public static void SetClipboardImage(Bitmap image, Bitmap imageNoTr, DataObject data)
{
Clipboard.Clear();
if (data == null)
data = new DataObject();
if (imageNoTr == null)
imageNoTr = image;
using (MemoryStream pngMemStream = new MemoryStream())
using (MemoryStream dibMemStream = new MemoryStream())
{
// As standard bitmap, without transparency support
data.SetData(DataFormats.Bitmap, true, imageNoTr);
// As PNG. Gimp will prefer this over the other two.
image.Save(pngMemStream, ImageFormat.Png);
data.SetData("PNG", false, pngMemStream);
// As DIB. This is (wrongly) accepted as ARGB by many applications.
Byte[] dibData = ConvertToDib(image);
dibMemStream.Write(dibData, 0, dibData.Length);
data.SetData(DataFormats.Dib, false, dibMemStream);
// The 'copy=true' argument means the MemoryStreams can be safely disposed after the operation.
Clipboard.SetDataObject(data, true);
}
}
/// <summary>
/// Converts the image to Device Independent Bitmap format of type BITFIELDS.
/// This is (wrongly) accepted by many applications as containing transparency,
/// so I'm abusing it for that.
/// </summary>
/// <param name="image">Image to convert to DIB</param>
/// <returns>The image converted to DIB, in bytes.</returns>
public static Byte[] ConvertToDib(Image image)
{
Byte[] bm32bData;
Int32 width = image.Width;
Int32 height = image.Height;
// Ensure image is 32bppARGB by painting it on a new 32bppARGB image.
using (Bitmap bm32b = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))
{
using (Graphics gr = Graphics.FromImage(bm32b))
gr.DrawImage(image, new Rectangle(0, 0, bm32b.Width, bm32b.Height));
// Bitmap format has its lines reversed.
bm32b.RotateFlip(RotateFlipType.Rotate180FlipX);
Int32 stride;
bm32bData = GetImageData(bm32b, out stride);
}
// BITMAPINFOHEADER struct for DIB.
Int32 hdrSize = 0x28;
Byte[] fullImage = new Byte[hdrSize + 12 + bm32bData.Length];
//Int32 biSize;
WriteIntToByteArray(fullImage, 0x00, 4, true, (UInt32)hdrSize);
//Int32 biWidth;
WriteIntToByteArray(fullImage, 0x04, 4, true, (UInt32)width);
//Int32 biHeight;
WriteIntToByteArray(fullImage, 0x08, 4, true, (UInt32)height);
//Int16 biPlanes;
WriteIntToByteArray(fullImage, 0x0C, 2, true, 1);
//Int16 biBitCount;
WriteIntToByteArray(fullImage, 0x0E, 2, true, 32);
//BITMAPCOMPRESSION biCompression = BITMAPCOMPRESSION.BITFIELDS;
WriteIntToByteArray(fullImage, 0x10, 4, true, 3);
//Int32 biSizeImage;
WriteIntToByteArray(fullImage, 0x14, 4, true, (UInt32)bm32bData.Length);
// These are all 0. Since .net clears new arrays, don't bother writing them.
//Int32 biXPelsPerMeter = 0;
//Int32 biYPelsPerMeter = 0;
//Int32 biClrUsed = 0;
//Int32 biClrImportant = 0;
// The aforementioned "BITFIELDS": colour masks applied to the Int32 pixel value to get the R, G and B values.
WriteIntToByteArray(fullImage, hdrSize + 0, 4, true, 0x00FF0000);
WriteIntToByteArray(fullImage, hdrSize + 4, 4, true, 0x0000FF00);
WriteIntToByteArray(fullImage, hdrSize + 8, 4, true, 0x000000FF);
Array.Copy(bm32bData, 0, fullImage, hdrSize + 12, bm32bData.Length);
return fullImage;
}
public static void WriteIntToByteArray(Byte[] data, Int32 startIndex, Int32 bytes, Boolean littleEndian, UInt32 value)
{
Int32 lastByte = bytes - 1;
if (data.Length < startIndex + bytes)
throw new ArgumentOutOfRangeException("startIndex", "Data array is too small to write a " + bytes + "-byte value at offset " + startIndex + ".");
for (Int32 index = 0; index < bytes; index++)
{
Int32 offs = startIndex + (littleEndian ? index : lastByte - index);
data[offs] = (Byte)(value >> (8 * index) & 0xFF);
}
}
public static UInt32 ReadIntFromByteArray(Byte[] data, Int32 startIndex, Int32 bytes, Boolean littleEndian)
{
Int32 lastByte = bytes - 1;
if (data.Length < startIndex + bytes)
throw new ArgumentOutOfRangeException("startIndex", "Data array is too small to read a " + bytes + "-byte value at offset " + startIndex + ".");
UInt32 value = 0;
for (Int32 index = 0; index < bytes; index++)
{
Int32 offs = startIndex + (littleEndian ? index : lastByte - index);
value += (UInt32)(data[offs] << (8 * index));
}
return value;
}
/// <summary>
/// Creates a bitmap based on data, width, height, stride and pixel format.
/// </summary>
/// <param name="sourceData">Byte array of raw source data</param>
/// <param name="width">Width of the image</param>
/// <param name="height">Height of the image</param>
/// <param name="stride">Scanline length inside the data</param>
/// <param name="pixelFormat">Pixel format</param>
/// <param name="palette">Color palette</param>
/// <param name="defaultColor">Default color to fill in on the palette if the given colors don't fully fill it.</param>
/// <returns>The new image</returns>
public static Bitmap BuildImage(Byte[] sourceData, Int32 width, Int32 height, Int32 stride, PixelFormat pixelFormat, Color[] palette, Color? defaultColor)
{
Bitmap newImage = new Bitmap(width, height, pixelFormat);
BitmapData targetData = newImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, newImage.PixelFormat);
Int32 newDataWidth = ((Image.GetPixelFormatSize(pixelFormat) * width) + 7) / 8;
// Compensate for possible negative stride on BMP format.
Boolean isFlipped = stride < 0;
stride = Math.Abs(stride);
// Cache these to avoid unnecessary getter calls.
Int32 targetStride = targetData.Stride;
Int64 scan0 = targetData.Scan0.ToInt64();
for (Int32 y = 0; y < height; y++)
Marshal.Copy(sourceData, y * stride, new IntPtr(scan0 + y * targetStride), newDataWidth);
newImage.UnlockBits(targetData);
// Fix negative stride on BMP format.
if (isFlipped)
newImage.RotateFlip(RotateFlipType.Rotate180FlipX);
// For indexed images, set the palette.
if ((pixelFormat & PixelFormat.Indexed) != 0 && palette != null)
{
ColorPalette pal = newImage.Palette;
for (Int32 i = 0; i < pal.Entries.Length; i++)
{
if (i < palette.Length)
pal.Entries[i] = palette[i];
else if (defaultColor.HasValue)
pal.Entries[i] = defaultColor.Value;
else
break;
}
newImage.Palette = pal;
}
return newImage;
}
/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <param name="stride">Stride of the retrieved image data.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageData(Bitmap sourceImage, out Int32 stride)
{
BitmapData sourceData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat);
stride = sourceData.Stride;
Byte[] data = new Byte[stride * sourceImage.Height];
Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
sourceImage.UnlockBits(sourceData);
return data;
}
好厉害的思路,感谢~
我刚好也遇到这个问题,刚好这个问题的需求是“表格转图片”,分享一下我的解决办法:
这比先粘贴为图片再剪切更麻烦了
粘贴 > 导入 >导出图片
原来我需要的是转换格式啊,需求不同
设个赞啊,完全没见过这个页面
这…隐藏的好深啊……不像excel能直接从复制按钮展开
厉害了,office提供了300%的功能给我们使用…
你的目的是要把这个表格转化成图片而已,没必要纠结用wrod插件或者word本身。其实用以下的方法步数都是差不多的。