Today I wanted to save a Bitmap to a .bmp file. I couldn't find anything
useful in the image, so I searched old posts using DSDN. Among others, I found an article from Andy dated 3rd November 1998 where he wrote: >Unfortunately there is no method to directly save a bitmap to a file (MS >didn't make it that easy). >You'll have to do this with a number of API calls. Is this still true or is there another way to do it now? Sincerely, Mikael Svane [hidden email] |
"Mikael Svane" <[hidden email]> wrote in message
news:93899s$995vt$[hidden email]... > Today I wanted to save a Bitmap to a .bmp file. I couldn't find anything > useful in the image, so I searched old posts using DSDN. Among others, I > found an article from Andy dated 3rd November 1998 where he wrote: > > >Unfortunately there is no method to directly save a bitmap to a file (MS > >didn't make it that easy). > >You'll have to do this with a number of API calls. > > Is this still true or is there another way to do it now? I don't know if this will help you, but here is the method from QKS Smalltalk for reading a DIB directly from a file. Obviously the reverse will write it out to a file. ... -- Dave Simmons [www.qks.com / www.smallscript.com] "Effectively solving a problem begins with how you express it." > > Sincerely, > > Mikael Svane > [hidden email] > fromFile: aFileSpecifierOrPath <annotations> Description: Return a new instance of the receiver based on the data from the specified file. Method Author: 'David Simmons'. Method Updated: 'Wed 07/30/1997 05:24:54 PM (PDT)'. Browse Category: 'instance creation'. Method Scope: Default. Scope Access: 'public-extended'. Method Type: 'factory'. Method Interface: none. Method Returns: none. Method Throws: none. </annotations> | specifier stream nBytes inst | Coerce paths to specifiers (specifier := (aFileSpecifierOrPath ? [^nil]) asSpecifier) ? [^nil]. Now attempt to open it (stream := specifier asReadStream) ? [^nil]. Now allocate a new instance and read the value into the instance. nBytes := stream seekLimit-14. stream position: 14; read: nBytes into: (inst := DIBitmap basicNewStorage: nBytes); close. After closing the stream, return the configured instance ^inst /* typedef struct tagBITMAPFILEHEADER { // bmfh WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; */ |
In reply to this post by Mikael Svane
Mikael,
> Is this still true or is there another way to do it now? I've got a Bitmap subclass that can be used as a normal Bitmap but can also be saved as a file. There's a bit more to it than you might imagine, you have to get involved in colour tables and bitmap structures, but it seems to work as expected. It is a bit more inefficient than the existing Bitmap subclasses, memory wise, so I tend to only use it for bitmaps that I know want to file out but _theoretically it could be used in place all the Dolphin bitmaps. It (the DeviceIndependentBitmap package) has been sitting on my system for some time now waiting to be uploaded as a goodie, I just can't get round to the documentation. I'll try to do it in the next few days but let me know if you want a copy mailed to you before that. Ian |
In reply to this post by Mikael Svane
Mikael
"Mikael Svane" <[hidden email]> wrote in message news:93899s$995vt$[hidden email]... > Today I wanted to save a Bitmap to a .bmp file. I couldn't find anything > useful in the image, so I searched old posts using DSDN. Among others, I > found an article from Andy dated 3rd November 1998 where he wrote: > > >Unfortunately there is no method to directly save a bitmap to a file (MS > >didn't make it that easy). > >You'll have to do this with a number of API calls. > > Is this still true or is there another way to do it now? Loading bitmaps from files is of course very easy since there is a Win32 API call to do it (LoadImage() passing the LR_LOADFROMFILE flag), and this is what all the various Dolphin Image subclasses (Bitmap, Icon, Cursor, etc) use to implement #loadFromFile:. Unfortunately Microsoft don't (or at least did not, one would have to check MSDN for the current state of play) provide a similar API call to save a BMP. It is relatively easy to do, however, (the on-disk format is essentially the same as the in-memory representation of a DIB, Device-Independent Bitmap). As Ian points out, he has code to do this as well in his DIBitmap goodie, and one can also find example code on MSDN. The preferred form of Bitmap these days is a DIBSection. This combines the device-independence of the older DIB format, and the efficiency of the plain on old device-dependent Bitmap. I'd imagine code to directly save these could be found, and I'd start with checking MSDN. An alternative is to make use of the services of OLEPicture. An example: We'll start off with a JPEG, as OLEPicture can load and then save these in bmp form. o := OLEPicture fromFile: 'Resources\Dolphin1.jpg'. Test to see if it is what we are expecting: ImagePresenter show value: o. Now save it to a file: s := IStream onHGLOBAL. o picture saveAsFile: s fSaveMemCopy: true. (FileStream write: 'c:\test.bmp' text: false) nextPutAll: s contents; close. (Hmmm, this looks like the makings of #saveAsFile: method for OLEPicture) And then view that: ImagePresenter show value: (DIBSection fromFile: 'c:\test.bmp'). Note that this will be inefficient for large bitmaps because the bitmap is written first to an in memory stream, before being written to disk as a byte image. AFAIK Microsoft do not provide an implementation of IStream that sits directly on top of a raw OS file (odd that). I have code on the shelf which implements the COM interface <IStream> directly onto a Dolphin FileStream though, if I could just find it. In the meantime a more efficient form would be: s := IStream onHGLOBAL. byteSize := o picture saveAsFile: s fSaveMemCopy: true. hglobal := s handle. (File open: 'c:\test.bmp') write: (KernelLibrary default globalLock: hglobal) count: byteSize; close. KernelLibrary default globalUnlock: hglobal So the method I've attached uses (essentially) this messier form. Regards Blair ---------------------- !OLEPicture methodsFor! saveAsFile: pathString "Save this picture to a file at the specified path, and existing file at that path is overwritten." | stream hglobal byteSize pBytes | stream := IStream onHGLOBAL. byteSize := self picture saveAsFile: stream fSaveMemCopy: true. hglobal := stream handle. pBytes := KernelLibrary default globalLock: hglobal. [ (File open: pathString) write: pBytes count: byteSize; close ] ensure: [KernelLibrary default globalUnlock: hglobal]! ! !OLEPicture categoriesFor: #saveAsFile:!file operations!public! ! begin 666 OLEPicture_saveAsFile.st M(4],15!I8W1U<F4@;65T:&]D<T9O<B$-"@T*<V%V94%S1FEL93H@<&%T:%-T M<FEN9PT*"2)3879E('1H:7,@<&EC='5R92!T;R!A(&9I;&4@870@=&AE('-P M96-I9FEE9"!P871H+"!A;F0@97AI<W1I;F<@9FEL92!A="!T:&%T#0H)<&%T M:"!I<R!O=F5R=W)I='1E;BXB#0H-"@E\('-T<F5A;2!H9VQO8F%L(&)Y=&53 M:7IE('!">71E<R!\#0H)<W1R96%M(#H]($E3=')E86T@;VY(1TQ/0D%,+@T* M"6)Y=&53:7IE(#H]('-E;&8@<&EC='5R92!S879E07-&:6QE.B!S=')E86T@ M9E-A=F5-96U#;W!Y.B!T<G5E+@T*"6AG;&]B86P@.CT@<W1R96%M(&AA;F1L M92X-"@EP0GET97,@.CT@2V5R;F5L3&EB<F%R>2!D969A=6QT(&=L;V)A;$QO M8VLZ(&AG;&]B86PN#0H)6PDH1FEL92!O<&5N.B!P871H4W1R:6YG*2 -"@D) M"7=R:71E.B!P0GET97,@8V]U;G0Z(&)Y=&53:7IE.R -"@D)"6-L;W-E#0H) M72!E;G-U<F4Z(%M+97)N96Q,:6)R87)Y(&1E9F%U;'0@9VQO8F%L56YL;V-K M.B!H9VQO8F%L72$@(0T*(4],15!I8W1U<F4@8V%T96=O<FEE<T9O<CH@(W-A G=F5!<T9I;&4Z(69I;&4@;W!E<F%T:6]N<R%P=6)L:6,A("$-"@T* ` end |
Blair,
Although Ians solution works fine, I wanted to try this one also. I filed in the code attached and replaced every instance of Bitmap with OLEPicture. Then I tried to save the package, but it complains about cyclic prerequisites: 1) My package has two prerequisites, Dolphin and OLE COM. 2) OLE COM also has two prerequisites, Dolphin and OLE Structured Storage. 3) OLE Structured Storage has two prerequisites, Dolphin and OLE COM, due to OLEPicture>>saveAsFile: that references the global IStream. 4) repeat from #2. Also there seems to be a problem when using loose methods with the little red arrow that indicates packages that were changed. Perhaps you are aware of this, but otherwise this reproduces the problem: 1) create a new package. 2) create a new method in one of the available classes, for example Model>>testMethod. This marks the package called Dolphin with a red arrow. 3) drag the method to the package you created. It appears in the Loose methods, but the package is not marked and Dolphin remains marked. 4) remove the method from your package. It remains in Loose methods until you select another package and then return to your package. 5) if you instead of number 3 above right click on the method in the CHB and select Package from the context menu, it doesn't appear in Loose methods until you select another package and then return. Your package still isn't marked with the arrow, but Dolphin, in this case, is. Since the arrow is so useful, it would be nice if it worked for loose methods too. Regards Mikael [hidden email] |
Mikael
"Mikael Svane" <[hidden email]> wrote in message news:93ambb$9g3ea$[hidden email]... >... > Then I tried to save the package, but it complains about cyclic > prerequisites: > > 1) My package has two prerequisites, Dolphin and OLE COM. > > 2) OLE COM also has two prerequisites, Dolphin and OLE Structured Storage. > > 3) OLE Structured Storage has two prerequisites, Dolphin and OLE COM, due to > OLEPicture>>saveAsFile: that references the global IStream. > > 4) repeat from #2. Yes, that is true. I should have mentioned that it is necessary to make OLEPicture>>saveAsFile: a loose method in in your own package. I assumed you would do this because otherwise you would lose the method if you saved your package and reloaded it into a fresh image, but I should have mentioned it instead of making assumptions. Sorry. > Also there seems to be a problem when using loose methods with the little > red arrow that indicates packages that were changed. Perhaps you are aware > of this, but otherwise this reproduces the problem: Thanks. We are aware of a bug that that Bob Jarvis (?) reported recently to do with Dolphin not updating the package change markers correctly when moving methods to become loose methods. If this is not the same thing, it is certainly related, so we will bear it in mind when looking into that. I'll just comment on one point to clear up a misunderstanding: > ... > 3) drag the method to the package you created. It appears in the Loose > methods, but the package is not marked and Dolphin remains marked. You're right, of course, that the target package should be marked as changed. However it is expected that Dolphin will remain marked, because as far as the system is concerned the package has still been changed. The change information is not held at a sufficient level of detail to determine that the method was the source of the original change, and that has now been moved out. This means you may need to clear change flags in Dolphin occassionally. (An aside for David Gorisek: David, what would STS do in this case?) > Since the arrow is so useful, it would be nice if it worked for loose > methods too. It it intended to, and we will fix this in a forthcoming maintenance (free upgrade) release. Regards Blair |
>Yes, that is true. I should have mentioned that it is necessary to make
>OLEPicture>>saveAsFile: a loose method in in your own package. I assumed you >would do this because otherwise you would lose the method if you saved your >package and reloaded it into a fresh image, but I should have mentioned it >instead of making assumptions. Sorry. > Ok. I thought that the method was so useful that I saved the image instead of doing what I would normally do (I keep all my changes in packages that I install every day). >> ... >> 3) drag the method to the package you created. It appears in the Loose >> methods, but the package is not marked and Dolphin remains marked. > >You're right, of course, that the target package should be marked as >changed. However it is expected that Dolphin will remain marked, because as >far as the system is concerned the package has still been changed. The >change information is not held at a sufficient level of detail to determine >that the method was the source of the original change, and that has now been >moved out. This means you may need to clear change flags in Dolphin >occassionally. > I had thought that it was the _method_ that was marked as changed and that a package that contained such a method would be marked with the arrow, but if it is the package that is marked, I understand why Dolphin behaves like this. Regards, Mikael [hidden email] |
Mikael
You wrote in message news:93da6a$9vd74$[hidden email]... > >Yes, that is true. I should have mentioned that it is necessary to make > >OLEPicture>>saveAsFile: a loose method in in your own package. I assumed > you > >would do this because otherwise you would lose the method if you saved your > >package and reloaded it into a fresh image, but I should have mentioned it > >instead of making assumptions. Sorry. > > > > > Ok. I thought that the method was so useful that I saved the image instead > of doing what I would normally do (I keep all my changes in packages that I > install every day). I'm not for one minute suggesting that you shouldn't save the image. The image is the state of the world, and should be saved, every few minutes or even more often. Not doing so is throwing away one of Smalltalk's greatest treasures. I know some people don't like to work like that, but I can only refer you to Andy's "You're all bonkers" posting (check Ian's archive) :-). Regards Blair |
Free forum by Nabble | Edit this page |