سؤال

أحاول إضافة صورة إلى وثيقة RTF التي أقوم بإنشاءها. أفضل عدم استخدام طرق "نسخ / لصق" (التي تنطوي على لصق الصورة داخل RichTextBox ثم الوصول إلى خاصية .RTF) التي تطهير الحافظة (لأن هذا سيكون عناء وارتباك للمستخدمين النهائيين).

يعود التعليمات البرمجية التي لدي حتى الآن السلسلة التي يجب إدراجها في وثيقة RTF لطباعة الصورة. عادة ما تكون الصورة المدخلة (الموجودة في مسار $) عادة بتنسيق BMP أو JPEG، ولكن في هذه المرحلة لا تهتم بكيفية تخزين الصورة داخل RTF فقط، يمكنني الحصول عليها للعمل.

public string GetImage(string path, int width, int height)
{
    MemoryStream stream = new MemoryStream();
    string newPath = Path.Combine(Environment.CurrentDirectory, path);
    Image img = Image.FromFile(newPath);
    img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);

    byte [] bytes = stream.ToArray();

    string str = BitConverter.ToString(bytes, 0).Replace("-", string.Empty);
    //string str = System.Text.Encoding.UTF8.GetString(bytes);

    string mpic = @"{\pict\pngblip\picw" + 
        img.Width.ToString() + @"\pich" + img.Height.ToString() +
        @"\picwgoa" + width.ToString() + @"\pichgoa" + height.ToString() + 
        @"\hex " + str + "}";
    return mpic
}

ومع ذلك، فإن المشكلة هي أن هذا الرمز لا يعمل لأنه بقدر ما أستطيع أن أخبره، لا يحتوي String Str على تحويل السلسلة الصحيحة للعمل داخل RTF.

عدل

هل كانت مفيدة؟

المحلول

جرب هذه الروابط

يجب تغيير "Picwgoa" إلى "Picwegoal" و "Pichgoa" إلى "Pichgoal"

string mpic = @"{\pict\pngblip\picw" + 
    img.Width.ToString() + @"\pich" + img.Height.ToString() +
    @"\picwgoal" + width.ToString() + @"\pichgoal" + height.ToString() + 
    @"\bin " + str + "}";

هنا لديك قائمة بتنسيقات الصور المدعومة

Emfblip المصدر للصورة هو EMF (ملف تعريف محسن).  PNGBLIP المصدر للصورة هو PNG.  jpegblip المصدر للصورة هو JPEG.  shppict يحدد صورة 97-2000 كلمة. هذه هي كلمة التحكم الوجهة.  NonShppict يحدد أن Word 97-2000 قد كتب وجهة { pict التي لن تقرأها على الإدخال. هذه الكلمة الرئيسية هي التوافق مع القراء الآخرين.  مصدر macpict للصورة هو QuickDraw.  Pmmetafilen المصدر للصورة هو ملف تعريف OS / 2. الحجة N تحدد نوع ملف التعريف. يتم وصف قيم N في جدول  pmmetafile أدناه.  Wmetafilen المصدر للصورة هو ملف تعريف ويندوز. تحدد الوسيطة N نوع ملف تعريف (الافتراضي هو 1).  Dibitmapn المصدر للصورة هو صورة نقطية مستقلة في نظام Windows. تحدد الوسيطة N نوع الصورة النقطية (يجب تساوي 0). المعلومات التي سيتم إدراجها في RTF من صورة نقطية مستقلة في نظام Windows هي سلسلة من بنية Bitmapinfo تليها بيانات البكسل الفعلية.  Wbitmapn مصدر الصورة هو صورة نقطية تعتمد على الجهاز. تحدد الوسيطة N نوع الصورة النقطية (يجب أن تساوي 0). المعلومات التي سيتم إدراجها في RTF من صورة نقطية تعتمد على جهاز Windows هي نتيجة وظيفة getbitmapbits.

نصائح أخرى

قضى يوم أو نحو ذلك إجابات googling لهذا. تجميعها معا الحكايات من جميع أنحاء Stackoverflow وغيرها من المصادر. إطعام هذه الصورة، وسوف ترجع السلسلة التي تحتاجها لإضافتها إلى ملحق RichTextBox.RTF. يتغير عرض الصورة ويحتاج إلى حسابه، وترد الصيغة.

    // RTF Image Format
    // {\pict\wmetafile8\picw[A]\pich[B]\picwgoal[C]\pichgoal[D]
    //  
    // A    = (Image Width in Pixels / Graphics.DpiX) * 2540 
    //  
    // B    = (Image Height in Pixels / Graphics.DpiX) * 2540 
    //  
    // C    = (Image Width in Pixels / Graphics.DpiX) * 1440 
    //  
    // D    = (Image Height in Pixels / Graphics.DpiX) * 1440 

    [Flags]
    enum EmfToWmfBitsFlags
    {
        EmfToWmfBitsFlagsDefault = 0x00000000,
        EmfToWmfBitsFlagsEmbedEmf = 0x00000001,
        EmfToWmfBitsFlagsIncludePlaceable = 0x00000002,
        EmfToWmfBitsFlagsNoXORClip = 0x00000004
    }

    const int MM_ISOTROPIC = 7;
    const int MM_ANISOTROPIC = 8;

    [DllImport("gdiplus.dll")]
    private static extern uint GdipEmfToWmfBits(IntPtr _hEmf, uint _bufferSize,
        byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags);
    [DllImport("gdi32.dll")]
    private static extern IntPtr SetMetaFileBitsEx(uint _bufferSize,
        byte[] _buffer);
    [DllImport("gdi32.dll")]
    private static extern IntPtr CopyMetaFile(IntPtr hWmf,
        string filename);
    [DllImport("gdi32.dll")]
    private static extern bool DeleteMetaFile(IntPtr hWmf);
    [DllImport("gdi32.dll")]
    private static extern bool DeleteEnhMetaFile(IntPtr hEmf);

        public static string GetEmbedImageString(Bitmap image)
        {
                Metafile metafile = null;
                float dpiX; float dpiY;

                using (Graphics g = Graphics.FromImage (image)) 
                {
                    IntPtr hDC = g.GetHdc ();
                    metafile = new Metafile (hDC, EmfType.EmfOnly);
                    g.ReleaseHdc (hDC);
                }

                using (Graphics g = Graphics.FromImage (metafile)) 
                {
                    g.DrawImage (image, 0, 0);
            dpiX = g.DpiX;
            dpiY = g.DpiY;
                }

                IntPtr _hEmf = metafile.GetHenhmetafile ();
                uint _bufferSize = GdipEmfToWmfBits (_hEmf, 0, null, MM_ANISOTROPIC,
                EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
                byte[] _buffer = new byte[_bufferSize];
                GdipEmfToWmfBits (_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC,
                                            EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
                IntPtr hmf = SetMetaFileBitsEx (_bufferSize, _buffer);
                string tempfile = Path.GetTempFileName ();
                CopyMetaFile (hmf, tempfile);
                DeleteMetaFile (hmf);
                DeleteEnhMetaFile (_hEmf);

                var stream = new MemoryStream ();
                byte[] data = File.ReadAllBytes (tempfile);
                //File.Delete (tempfile);
                int count = data.Length;
                stream.Write (data, 0, count);

                string proto = @"{\rtf1{\pict\wmetafile8\picw" + (int)( ( (float)image.Width / dpiX ) * 2540 )
                                  + @"\pich" + (int)( ( (float)image.Height / dpiY ) * 2540 )
                                  + @"\picwgoal" + (int)( ( (float)image.Width / dpiX ) * 1440 )
                                  + @"\pichgoal" + (int)( ( (float)image.Height / dpiY ) * 1440 )
                                  + " " 
                      + BitConverter.ToString(stream.ToArray()).Replace("-", "")
                                  + "}}";                   
                return proto;
        }

قد يجد الزوار لاحقا هذه الصفحة (مثل بضعة أيام) الرابط التالي مفيد: تحويل صورة إلى WMF مع .NET

سيجد المرء أن الدفتر يتجاهل أي صورة غير مخزنة في تنسيق ملف تعريف Windows المناسب. وبالتالي، فإن المثال السابق في هذه الصفحة لن تظهر على الإطلاق (على الرغم من أنه يعمل بشكل جيد فقط في OpenOffice و Word نفسه). التنسيق الذي سيدعمه الدفتر هو:

{/ PICT / WMETAFILE8 / PICW [العرض] / Pich [الارتفاع] / Picwegoal [ScaleDwidth] / Pichgoal [Scaledheight] [قيم الصورة-سلسلة من البايتات-العزبة]} (مع المصطلحات في الأقواس المربعة استبدالها البيانات المناسبة).

يمكن إجراء الحصول على "البيانات المناسبة" باتباع الإجراءات في الرابط أعلاه. بالنسبة لأولئك الذين لديهم ثعبون يبحثون عن حل، إليكم بداية واحدة (أعتقد أن بعض مشكلات DPI / Scaling تظل). هذا يتطلب بيل(أو وسادة), ctypes., ، و CLR (بيثون .NET). وبعد استخدم PIL / وسادة وفتح الصورة أولا. هنا لدي أنها مفتوحة ك "CANV":

from ctypes import *
import clr
clr.AddReference("System.IO")
clr.AddReference("System.Drawing")
from System import IntPtr
from System.Drawing import SolidBrush
from System.Drawing import Color
from System.Drawing import Imaging
from System.Drawing import Graphics
from System.IO import FileStream
from System.IO import FileMode
from System.IO import MemoryStream
from System.IO import File

def byte_to_hex(bytefile):
  acc = ''
  b = bytefile.read(1)
  while b:
    acc+=("%02X" % ord(b))
    b = bytefile.read(1)
  return acc.strip()

#... in here is some code where 'canv' is created as the PIL image object, and
#...   'template' is defined as a string with placeholders for picw, pich, 
#...   picwgoal, pichgoal, and the image data


mfstream     = MemoryStream()
offscrDC     = Graphics.FromHwndInternal(IntPtr.Zero)
imgptr       = offscrDC.GetHdc()
mfile        = Imaging.Metafile(mfstream, imgptr, Imaging.EmfType.EmfOnly)
gfx          = Graphics.FromImage(mfile)
width,height = canv.size
pixels       = canv.load()
for x in range(width):
  for y in range(height):
    _r,_g,_b = pixels[x, y]
    c     = Color.FromArgb(_r, _g, _b)
    brush = SolidBrush(c)
    gfx.FillRectangle(brush, x, y, 1, 1)
gfx.Dispose()
offscrDC.ReleaseHdc()
_hEmf            = mfile.GetHenhmetafile()
GdipEmfToWmfBits = windll.gdiplus.GdipEmfToWmfBits
_bufferSize      = GdipEmfToWmfBits(
                      int(str(_hEmf)),
                      c_uint(0),
                      None,
                      c_int(8),           # MM_ANISOTROPIC
                      c_uint(0x00000000)) # Default flags
_buffer = c_int * _bufferSize
_buffer = _buffer(*[0 for x in range(_bufferSize)])
GdipEmfToWmfBits( int(str(_hEmf)),
                  c_uint(_bufferSize),
                  _buffer,
                  c_int(8),            # MM_ANISOTROPIC
                  c_uint(0x00000000) ) # Default flags
hmf = windll.gdi32.SetMetaFileBitsEx(c_uint(_bufferSize), _buffer)
windll.gdi32.CopyMetaFileA(int(str(hmf)), "temp.wmf")
windll.gdi32.DeleteMetaFile(int(str(hmf)))
windll.gdi32.DeleteEnhMetaFile(int(str(_hEmf)))
mfstream.Close()

imgstr = open("temp.wmf", 'rb')
imgstr = byte_to_hex(imgstr)
with open('script-out.rtf','wb') as outf:
  template = template % (str(_cx),str(_cy),str(15*_cx),str(15*_cy),imgstr)
  outf.write(template)

لقد وجدت أن معظم صناديق RTF باستخدام التنسيق التالي:

{\object\objemb{\*\objclass Paint.Picture}\objw2699\objh4799{\*\objdata [hex/bin]}}

متي [hex/bin] هو كمية كبيرة من سلاسل عرافة تمثل تنسيق الصورة. بهذه الطريقة تعمل كل من Word RTF، وكلاهما لمربع RTF - لذلك هو أكثر كفاءة.

في صورة الكمبيوتر الخاصة بي بحجم 180 × 320 بكسل تم تحويلها إلى 2699 × 4799 موازين، مما يعني 1PIX = 15 موازين، بقدر ما أستطيع أن أرى، هو مثل هذا في 3 أجهزة كمبيوتر كنت اختبرت، بينها بين ويندوز إكس بي بروفيسور، ويندوز إكس بي المنزل والفوز 7.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top