Recent

Author Topic: Inserting, Saving and Loading Images  (Read 27000 times)

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Inserting, Saving and Loading Images
« on: September 12, 2016, 06:03:34 pm »
Quote
I suggest that you create another thread if you are still looking for a solution to save/load the images with files.

It basically needs an interface. Specifically IRichEditOleCallback interface. You pass an instance to the rich edit using EM_SETOLECALLBACK message.

For reading images it needs two functions implemented GetNewStorage and QueryInsertObject. One is to allocate space for the parsed images, while the other is to ask if you want to show the image. The rest of the interface functions can return E_NOTIMPL.

As for writing, I just tested EM_STREAMOUT. It embedded the image in the file successfully.

I have tried to find out information on the functions that you have listed. Documentations are terse. I have found an example, but it is in C code, and my knowledge of C is very limited.

Code: Pascal  [Select][+][-]
  1. private string ReadRTF(IntPtr handle)
  2. {
  3.     string result = String.Empty;
  4.     using (MemoryStream stream = new MemoryStream())
  5.     {
  6.         EDITSTREAM editStream = new EDITSTREAM();
  7.         editStream.pfnCallback = new EditStreamCallback(EditStreamProc);
  8.         editStream.dwCookie = stream;
  9.  
  10.         SendMessage(handle, EM_STREAMOUT, SF_RTF, editStream);
  11.  
  12.         stream.Seek(0, SeekOrigin.Begin);
  13.         using (StreamReader reader = new StreamReader(stream))
  14.         {
  15.             result = reader.ReadToEnd();
  16.         }
  17.     }
  18.     return result;
  19. }
  20.  
  21. private int EditStreamProc(MemoryStream dwCookie, IntPtr pbBuff, int cb, out int pcb)
  22. {
  23.     pcb = cb;
  24.     byte[] buffer = new byte[cb];
  25.     Marshal.Copy(pbBuff, buffer, 0, cb);
  26.     dwCookie.Write(buffer, 0, cb);
  27.     return 0;
  28. }
  29.  
  30. private delegate int EditStreamCallback(MemoryStream dwCookie, IntPtr pbBuff, int cb, out int pcb);
  31.  
  32. [StructLayout(LayoutKind.Sequential)]
  33. private class EDITSTREAM
  34. {
  35.     public MemoryStream dwCookie;
  36.     public int dwError;
  37.     public EditStreamCallback pfnCallback;
  38. }
  39.  
  40. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  41. private static extern IntPtr SendMessage(HandleRef hwnd, uint msg, uint wParam, ref EDITSTREAM lParam);
  42.  
  43. public const int WM_USER = 0x0400;
  44. public const int EM_STREAMOUT = WM_USER + 74;
  45. public const int SF_RTF = 2;
  46.  
  47. //apply the above
  48.  
  49. here's how you can call this:
  50.  
  51. string temp = ReadRTF(richTextBox1.Handle);
  52. Console.WriteLine(temp);
  53. on my test richedit this returns following string:
  54.  
  55. {\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}} \viewkind4\uc1\pard\qc\f0\fs17 test paragraph\par \pard test paragraph\par }
  56.  
  57. static DWORD CALLBACK
  58. MyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
  59. {
  60.         HANDLE pFile = (HANDLE) dwCookie;
  61.         DWORD dwW;
  62.         WriteFile(pFile,pbBuff,cb,&dwW,NULL);
  63.         *pcb = cb;
  64.  
  65.         return 0;
  66. }
  67.  
  68. void SaveTest(HWND hWnd, int nIDDlgItem)
  69. {
  70.         HANDLE hFile = CreateFile("c:\\myfile.rtf",GENERIC_WRITE,0,NULL,
  71.                 CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  72.  
  73.         EDITSTREAM es;
  74.  
  75.         es.dwCookie = (DWORD) &hFile;
  76.         es.pfnCallback = MyStreamOutCallback;
  77.  
  78.         SendDlgItemMessage(hWnd,nIDDlgItem,EM_STREAMOUT,(WPARAM)SF_RTF,(LPARAM)&es);
  79.  
  80.         CloseHandle(hFile);
  81. }
  82.  
  83. The above line might be wrong:
  84.  
  85. es.dwCookie = (DWORD) &hFile;
  86.  
  87. You're passing the address of the file's handle, not the handle itself, which is what your MyStreamOutCallback() function is expecting. Just try
  88.  
  89. es.dwCookie = (DWORD) hFile;
  90.  
  91. -Mike
  92.  
  93. By the way, EM_STREAMIN/EM_STREAMOUT can load or save unicode content to/from a file if the flag SF_UNICODE is set:
  94.  
  95. SendMessageW(richeditWindow, EM_STREAMOUT, (WPARAM) SF_TEXTIZED | SF_UNICODE, (LPARAM) &eds);
  96.  

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Inserting, Saving and Loading Images
« Reply #1 on: September 12, 2016, 06:56:44 pm »
I have found an example, but it is in C code, and my knowledge of C is very limited.
That's C# btw. Ugh, the code is pure WinAPI, guess I've lost that knowledge long time ago.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Inserting, Saving and Loading Images
« Reply #2 on: September 12, 2016, 09:51:01 pm »
The example you found does not load images.

Attached with this post a small example. You will notice that btnLoad without btnOLE does not show images.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #3 on: September 14, 2016, 01:32:33 pm »
engkin,

Thanks. I will look at your example.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #4 on: September 14, 2016, 01:51:33 pm »
engkin,

Your example work perfectly. I inserted a call into btnLoad that activates btnOLE. It worked, but is there anything wrong with doing that?

I have to say that your code is "way simple and efficient." I am grateful.

Code: Pascal  [Select][+][-]
  1. procedure TCmdForm.btnLoadClick(Sender: TObject);
  2. var
  3.   fs: TFileStream;
  4. begin
  5.   btnOLEClick(self);   //*** inserted call ***
  6.   if OpenDialog1.Execute then
  7.   begin
  8.     fs := TFileStream.Create(OpenDialog1.FileName, fmOpenRead or fmShareDenyNone);
  9.     try
  10.       PageMemo.LoadRichText(fs);
  11.     finally
  12.       fs.Free;
  13.     end;
  14.   end;
  15. end;
  16.  
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Inserting, Saving and Loading Images
« Reply #5 on: September 14, 2016, 03:32:04 pm »
 :o
I'd never thought that assigning OLE callback is that critical for embedded objects to be loaded. (having this implemented by default in RichEdit control would make more sense, as it seems doing now in Windows 8 and later)

At least that explains the difference why wordpad loads images and RM doesn't.

I've added creation of the OLE callback for RichMemo by default in r5159. Thus you shouldn't need to create the object yourself.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #6 on: September 14, 2016, 04:18:29 pm »
skalogryz,

Thank you much.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Inserting, Saving and Loading Images
« Reply #7 on: September 14, 2016, 05:04:03 pm »
thanks should go to engkin :)

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #8 on: September 14, 2016, 05:34:18 pm »
I loaded r5159. This change has also permitted the image to be selected and dragged to another location.

Do you think it might be possible to access its properties to alter width and height?

And, big thanks to engkin!
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Inserting, Saving and Loading Images
« Reply #9 on: September 14, 2016, 06:03:14 pm »
Do you think it might be possible to access its properties to alter width and height?
Do you mean programmatically? from UI perspective you should be able to click it and resize it.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #10 on: September 14, 2016, 06:32:00 pm »
Correct. I forgot to mention that it can be clicked and stretched. I want to do it by code so that I can resize it proportionately. Distorted images by hand dragging are not useful to me.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #11 on: September 14, 2016, 08:52:39 pm »
The OLE allows for dragging a node for dynamically resizing the image. Can that be modified so that a corner node will be proportional? The sides would allow distortion.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #12 on: September 14, 2016, 09:29:54 pm »
I have noticed a problem. The image isn't always selectable. Additional images cannot be selected.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Inserting, Saving and Loading Images
« Reply #13 on: September 14, 2016, 09:38:20 pm »
I have noticed a problem. The image isn't always selectable. Additional images cannot be selected.
you might want to see if Wordpad behaves in the same manner. If it does... it might be unfixable.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Inserting, Saving and Loading Images
« Reply #14 on: September 14, 2016, 10:01:54 pm »
it just occurred to me... I am doing additional inserts. It may mean that the insert code needs a OLE callback.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

 

TinyPortal © 2005-2018