18

I have been creating reports by copying some charts and data from an excel document into a word document. I am pasting into a content control, so i use ChartObject.CopyPicture in excel and ContentControl.Range.Paste in word. This is done in a loop:

Set ws = ThisWorkbook.Worksheets("Charts")
With ws
For Each cc In wordDocument.ContentControls

    If cc.Range.InlineShapes.Count > 0 Then
        scaleHeight = cc.Range.InlineShapes(1).scaleHeight
        scaleWidth = cc.Range.InlineShapes(1).scaleWidth
        cc.Range.InlineShapes(1).Delete
        .ChartObjects(cc.Tag).CopyPicture Appearance:=xlScreen, Format:=xlPicture
        cc.Range.Paste
        cc.Range.InlineShapes(1).scaleHeight = scaleHeight
        cc.Range.InlineShapes(1).scaleWidth = scaleWidth
    ElseIf ...
Next cc
End With

Creating these reports using Office 2007 yielded files that were around 6MB, but creating them (using the same worksheet and document) in Office 2010 yields a file that is around 10 times as large.

After unzipping the docx, I found that the extra size comes from emf files that correspond to charts that are pasted in using VBA. Where they range from 360 to 900 KB before, they are 5-18 MB. And the graphics are not visibly better.

Even further, it seems to be related to the Chart Style. I created a new spreadsheet and inserted 7 data points and a corresponding 2D pie chart. With the default style, it copied as a 79 KB emf, and with style 26 it copies as a 10 MB emf. When I was using Office 2007, the chart would copy as a 700 KB emf. This is the code:

Sub CopyAndPaste()
    ThisWorkbook.Worksheets("Charts").ChartObjects("Chart 1").CopyPicture Appearance:=xlScreen, Format:=xlPicture
    GetObject(, Class:="Word.Application").ActiveDocument.Range.Paste
End Sub

I am able to CopyPicture with the format xlBitmap, and while that is somewhat smaller, it is larger than the emf generated by Office 2007 and noticeably poorer quality. Are there any other options for reducing the file size? Ideally, I would like to produce a file with the same resolution for the charts as I did using Office 2007. Is there any way that uses VBA only (without modifying the charts in the spreadsheet)? Any way I can easily copy as an object without linking the documents?

Kazimierz Jawor
  • 18,861
  • 7
  • 35
  • 55
Steve Clanton
  • 4,064
  • 3
  • 32
  • 38
  • 3
    There were some changes to charting in Excel 2010: [see this blog](http://blogs.office.com/2009/08/25/more-charting-enhancements-in-excel-2010/), though none stand out as an obvious cause. Are you using `CopyPicture Appearance:=xlPrinter` as this gives larger files than `xlScreen`? Otherwise, can you give a bit more detail on the charts (what type, what kind of formatting, how many data points)? – aucuparia May 28 '14 at 13:04
  • 5
    How about exporting the chart in a more efficient format (something like `ActiveChart.Export "C:\My Charts\SpecialChart.png"`) and then importing the .png into Word? Should be a manageable file size. – Rick May 28 '14 at 13:06
  • Could you add the actual code you are using? Are you including links to the data when pasting? – Adach1979 May 28 '14 at 15:58
  • I don't want the spreadsheet and document to be linked. There is not a link included when pasting, just an emf file in the media folder of the docx. – Steve Clanton May 28 '14 at 16:32
  • I am using xlScreen, and there is nothing that stands out about the charts. None of them use more than two dozen data points and most use less than 15. – Steve Clanton May 28 '14 at 21:29
  • I think it is related to the Chart Style, which is "Style 26." – Steve Clanton May 28 '14 at 22:30
  • 1
    What is the chart type? In my testing, file sizes were all reasonable except for charts with curved 3D objects (of which 3D bubble was the worst). I'm guessing that the way Excel 2010 renders these to a metafile is very inefficient compared to 2007. – aucuparia May 29 '14 at 07:32
  • 1
    [Someone else with this problem](http://social.technet.microsoft.com/Forums/fr-FR/feddccc6-7f99-46f1-9e39-1bdae985c2b1/problems-inserting-excel-chart-as-word-enhanced-metafile-office-2010?forum=word) (not a pretty solution - copy via PDF) – aucuparia May 29 '14 at 14:01
  • I created a new spreadsheet and inserted 7 data points and a corresponding 2D pie chart. With the default style, it copied as a 79 KB emf, and with style 26 it copies as a 10 MB emf. – Steve Clanton May 29 '14 at 14:14
  • 2
    It seems that the reason for the increased file size has to do with a high-resolution image saved in addition to the emf file: http://eknowinf.wordpress.com/2011/12/08/microsoft-office-2010-lacking-support-for-vector-graphics/ – MP24 Jun 02 '14 at 20:21
  • Have you tried playing with the *Image Size and Quality* options under *Word Options > Advanced*? – MP24 Jun 02 '14 at 20:28
  • @MP24 Thanks for the suggestion. I have tried it, and the changes do not seem to change the size of the emf. I could possibly try it in combination with importing the file as a png or bmp rather than pasting. However, I have become somewhat convinced that I am going to have to create a chart object in word as the final solution here. – Steve Clanton Jun 02 '14 at 20:38
  • Another suggestion is to use simple styles only as complex styles will create thousands of small objects: http://answers.microsoft.com/en-us/office/forum/office_2010-excel/large-enhanced-metafile/bf753bf0-5ab3-4e99-9b80-b23d507857f4 – MP24 Jun 02 '14 at 20:49
  • Not seen this mentioned in the comments and not sure if it would make a difference to an exported image size, but before exporting the image of the chart from excel, try and run the "Compress Pictures" option. It can be done by code with SendKeys or just with minimal user interaction. I use something similar once my image is placed into an excel sheet... `ActiveSheet.DrawingObjects.Select [NEWLINE] MsgBox "Dont forget to tick the Apply to Selected Pictures box", vbOKOnly + vbInformation [NEWLINE] Application.CommandBars.ExecuteMso "PicturesCompress"` – bmgh1985 Jun 06 '14 at 15:28
  • 1
    In place of a straight .Paste, what about using .PasteSpecial Link:=False, DataType:=wdPasteEnhancedMetafile ? – variant Jun 10 '14 at 14:33

3 Answers3

1

I've dealt with something like this before

Instead of using

Document.Range.Paste

Try Using

Document.Range.PasteSpecial DataType:= wdPasteMetafilePicture

or

Document.Range.PasteSpecial DataType:= wdPasteShape

This will paste the chart as a picture or drawing as opposed to an embedded excel object

Equivelant to using "Paste Special..." from the menu.

Other DataTypes are available

http://msdn.microsoft.com/en-us/library/office/aa220339(v=office.11).aspx

Tom Page
  • 1,211
  • 1
  • 7
  • 8
1

"It's an older code, sir, but it checks out."

It's an old question and I have an even older (possible) solution: you can compress your .EMF files as .EMZ by gzipping it. This will reduce your file size while keeping the image quality.

On VB6 I used zlib.dll and the code below. I renamed the function names to english but I kept all comments in portuguese:

Option Explicit

' Declaração das interfaces com a ZLIB
Private Declare Function gzopen     Lib "zlib.dll" (ByVal file As String, ByVal mode As String) As Long
Private Declare Function gzwrite    Lib "zlib.dll" (ByVal file As Long, ByRef uncompr As Byte, ByVal uncomprLen As Long) As Long
Private Declare Function gzclose    Lib "zlib.dll" (ByVal file As Long) As Long
Private Declare Function Compress   Lib "zlib.dll" Alias "compress" (ByRef dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long) As Long
Private Declare Function Uncompress Lib "zlib.dll" Alias "uncompress" (ByRef dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long) As Long

' Ler o conteúdo de um arquivo
Public Function FileRead(ByVal strNomeArquivo As String) As Byte()

    Dim intHandle     As Integer
    Dim lngTamanho    As Long
    Dim bytConteudo() As Byte

    On Error GoTo FileReadError

    ' Abrir o documento indicado
    intHandle = FreeFile
    Open strNomeArquivo For Binary Access Read As intHandle

    ' Obter o tamanho do arquivo
    lngTamanho = LOF(intHandle)
    ReDim bytConteudo(lngTamanho)

    ' Obter o conteúdo e liberar o arquivo
    Get intHandle, , bytConteudo()
    Close intHandle

    FileRead = bytConteudo

    On Error GoTo 0
    Exit Function

FileReadError:

    objLogger.GravarEvento "modZLib.FileRead: " & Err.Description & " (" & Err.Number & " - " & Err.Source & ")", logTipoEvento.Erro

End Function

'Compactar um arquivo com o padrão gzip
Public Sub FileCompress(ByVal strArquivoOrigem As String, ByVal strArquivoDestino As String)

    Dim gzFile        As Long
    Dim bytConteudo() As Byte

    On Error GoTo FileCompressError

    ' Ler o conteúdo do arquivo
    bytConteudo = FileRead(strArquivoOrigem)

    ' Compactar o conteúdo
    gzFile = gzopen(strArquivoDestino, "wb")
    gzwrite gzFile, bytConteudo(0), UBound(bytConteudo)
    gzclose gzFile

    On Error GoTo 0
    Exit Sub

FileCompressError:

    objLogger.GravarEvento "modZLib.FileCompress:" & Err.Description & " (" & Err.Number & " - " & Err.Source & ")", logTipoEvento.Erro

End Sub
Rubens Farias
  • 57,174
  • 8
  • 131
  • 162
  • As much as I want there to be something better, this is better than anything else I've found. I think this is the best that can be done. Thanks. – Steve Clanton Apr 26 '15 at 22:51
0

This is possibly happening because the .emf files are getting scaled incorrectly. Using PNG may resolve the size issue (as mentioned in the comments above), but will still be an issue because they will not be vector images.

If you use AddPicture to add images to your file, then the following page shows a solution wherein you can change the scale and reduce filesize from whatever default is being used. So it might solve your issue.

http://social.msdn.microsoft.com/Forums/en-US/f1c9c753-77fd-4c17-9ca8-02908debca5d/emf-file-added-using-the-addpicture-method-looks-bigger-in-excel-20072010-vs-excel-2003?forum=exceldev

hnk
  • 2,216
  • 1
  • 13
  • 18