|
First of all, I just want to thank you for writing this class. It was exactly what I needed!
In exchange, I would like to contribute some suggestions for any future versions.
- Make it template based (the ATL version, at least)
The base class, CWindowImpl<> takes two additional parameters that are currently being left to the default values. It would be better if the CPictureExWnd class would itself be a template that takes these values as parameters.
If you name class template somelike CPictureExWndT, and then specify a typedef with the name CPictureExWnd, no one would have to change their code (unless they wanted to make use of this new utility).
Why would anyone want to do this? Well, in the ATL samples, there is a file called "atlcontrols.h" . It provides template classes to support lots of common controls. You could substitute AtlControls::CStatic instead of CWindow, and it would add the helper functions for Static controls.
Another idea would be to create a button control that animates the GIF whenever someone mouses over it. All you would need to do is specify AtlControls::CButton and in a derived class declare another DECLARE_WND_SUPERCLASS that specifies BUTTON instead of STATIC, and then add a chained message map to handle the messages. The downside would be that it would be expensive to create/destroy the thread whenever it mouses over, but that brings me to my next suggestion...
- Allow Pause/Resume of the thread
You could add a couple of member functions that will suspend/resume the thread instead of destroying/creating it everytime. Useful if you want to pause the animation frequently.
- Support jumping to a given frame
To be used in conjunction with the above, if you wanted to rewind the animation to the beginning everytime you start it up, or something along those lines.
- Inline Some Functions
If you inline some of the smaller functions, especially the ones that just return values, it helps the compiler to optimize the code if you specify the functions as inline.
---
Darrin W. Cullop
|
|
|
|
|
Great suggestions, Darrin! Some of them make me go doh. Along with true transparency support it looks like it will make a perfect v1.4 release. Thanks again!
|
|
|
|
|
Hi,
How should I use this class for creating shell extension for animated gif's within rightclick menu - similar to PicAview from acdsee.com look at:
http://www.acdsystems.com/English/Products/ImagingProducts/Utilities/Picaview/index.htm
|
|
|
|
|
You can call CPictureEx[Wnd]::Create directly and pass to it the handle of a window you wish to be a GIF's parent. Then just Load() a picture and Draw() it.
|
|
|
|
|
Initialization of the extension - GifAniShlExt::Initialize() - does not seem to be a problem. The problem is a GIF parent window as you call it - It would be a menu and I guess I would need to use MENUITEMINFO for using my preview.
Is there smth special I should be aware of?
|
|
|
|
|
First I want to thank Mr. Oleg Bykov for contributing such a useful class.
But I found one small bug inside the member function CPictureEx::ThreadAnimation(), here is the line:
const int nUnitsPerSecond = 100000; //<== Instead of 100000, it acutally should be 10000000.
// Because the Timer unit is 100-nanoseconds.
// ( 1 second = 1,000 milliseconds = 1,000,000 microseconds = 10,000,000 100-nanoseconds )
The waitable timer is only available in WinNT 4.0 & Win98 above version. To make this class also workable under Win95. We need replace the waitable timer. Here are my modifications: All the modifications are inside the compiler conditional block(#ifdef #else #endif):
(After making this modification, I realize that there is no need to put the waitable timer here. We can always use the WaitForSingleObject's timeout to safely sleep a period of time without delaying any stop request during this peroid. Am I right?)
void CPictureEx::ThreadAnimation()
{
#ifdef Win98NT
HANDLE hTimer = CreateWaitableTimer(NULL,TRUE,NULL);
if (!hTimer)
{
TRACE(_T("ThreadAnimation: couldn't create a waitable timer\n"));
return;
};
#endif
#ifdef Win98NT
// we're gonna wait for two events, whichever occurs first
// this way we won't have lags with lengthy GIF-delays
HANDLE arrHandles[2] = {hTimer, m_hExitEvent};
#endif
int nTemp = 0;
while (!m_bExitThread)
{
if (m_arrFrames[nTemp].m_pPicture)
{
///////////////////////////////////////////////////////
// Before rendering a frame we should take care of what's
// behind that frame. TFrame::m_nDisposal will be our guide:
// 0 - no disposal specified (do nothing)
// 1 - do not dispose (again, do nothing)
// 2 - restore to background color (m_clrBackground)
// 3 - restore to previous
//////// disposal method #3
HDC hMemDC = NULL;
HBITMAP hMemBM = NULL, hOldBM;
if (m_arrFrames[nTemp].m_nDisposal == 3)
{
// prepare a memory DC and store the background in it
hMemDC = CreateCompatibleDC(m_hMemDC);
hMemBM = CreateCompatibleBitmap(m_hMemDC,
m_arrFrames[nTemp].m_frameSize.cx,
m_arrFrames[nTemp].m_frameSize.cy);
if (hMemDC && hMemBM)
{
hOldBM = reinterpret_cast<hbitmap> (SelectObject(hMemDC,hMemBM));
BitBlt(hMemDC,0,0,
m_arrFrames[nTemp].m_frameSize.cx,
m_arrFrames[nTemp].m_frameSize.cy,
m_hMemDC,
m_arrFrames[nTemp].m_frameOffset.cx,
m_arrFrames[nTemp].m_frameOffset.cy,
SRCCOPY);
};
};
///////////////////////
long hmWidth;
long hmHeight;
m_arrFrames[nTemp].m_pPicture->get_Width(&hmWidth);
m_arrFrames[nTemp].m_pPicture->get_Height(&hmHeight);
if (m_arrFrames[nTemp].m_pPicture->Render(m_hMemDC,
m_arrFrames[nTemp].m_frameOffset.cx,
m_arrFrames[nTemp].m_frameOffset.cy,
m_arrFrames[nTemp].m_frameSize.cx,
m_arrFrames[nTemp].m_frameSize.cy,
0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
{
Invalidate(FALSE);
};
if (m_bExitThread)
{
if (hMemDC)
{
// dispose local variables
SelectObject(hMemDC,hOldBM);
DeleteDC(hMemDC);
DeleteObject(hMemBM);
};
break;
};
#ifdef Win98NT
LARGE_INTEGER li;
const int nUnitsPerSecond = 10000000;
if (m_arrFrames[nTemp].m_nDelay < 5)
li.QuadPart = -static_cast<long>(10*nUnitsPerSecond);
else
li.QuadPart = -(nUnitsPerSecond*static_cast<long>(m_arrFrames[nTemp].m_nDelay));
li.QuadPart /=100;
SetWaitableTimer(hTimer,&li,0,NULL,NULL,FALSE);
// of course, we could use a casual Sleep()
// but then Stop() would take quite some time
WaitForMultipleObjects(2,arrHandles,FALSE,10000);
#else
DWORD dwTime;
if (m_arrFrames[nTemp].m_nDelay < 5)
dwTime = 10*10;
else
dwTime = m_arrFrames[nTemp].m_nDelay*10;
WaitForSingleObject(m_hExitEvent,dwTime);
#endif
if (m_bExitThread)
{
if (hMemDC)
{
// dispose local variables
SelectObject(hMemDC,hOldBM);
DeleteDC(hMemDC);
DeleteObject(hMemBM);
};
break;
};
// disposal method #2
if (m_arrFrames[nTemp].m_nDisposal == 2)
{
HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
if (hBrush)
{
RECT rect = {
m_arrFrames[nTemp].m_frameOffset.cx,
m_arrFrames[nTemp].m_frameOffset.cy,
m_arrFrames[nTemp].m_frameOffset.cx + m_arrFrames[nTemp].m_frameSize.cx,
m_arrFrames[nTemp].m_frameOffset.cy + m_arrFrames[nTemp].m_frameSize.cy };
FillRect(m_hMemDC,&rect,hBrush);
DeleteObject(hBrush);
};
}
else
if (hMemDC && (m_arrFrames[nTemp].m_nDisposal == 3) )
{
// put it back
BitBlt(m_hMemDC,
m_arrFrames[nTemp].m_frameOffset.cx,
m_arrFrames[nTemp].m_frameOffset.cy,
m_arrFrames[nTemp].m_frameSize.cx,
m_arrFrames[nTemp].m_frameSize.cy,
hMemDC,0,0, SRCCOPY);
// dispose local variables
SelectObject(hMemDC,hOldBM);
DeleteDC(hMemDC);
DeleteObject(hMemBM);
};
};
nTemp++;
if (nTemp == m_arrFrames.size())
{
nTemp = 0;
// init the screen for the first frame,
RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
FillRect(m_hMemDC,&rect,(HBRUSH)(COLOR_WINDOW));
};
};
#ifdef Win98NT
CloseHandle(hTimer);
#endif
}
Wayne King
10 Oct 2001
|
|
|
|
|
Thank you for your kind words. You're absolutely right in both of your statements. First, I didn't pay attention to the fact that waitable timers are only available on Win98. Second, I didn't realize that I could use dwTimeOut parameter of WaitForSinlgeObject. Ironically enough, we had to solve the similar problem with our current project and one of my co-workers showed me this solution. Unfortunately, the article was already submitted.
I'll definitely redo the class to make it more compatible. Thanks again, I'll surely mention you in the new article.
|
|
|
|
|
As far as I know, including support for GIF files in your application requieres paying royalties to the guys who patented the GIF format.
If I use this class in my app, even if it is totally free, I still have to pay the royalties, or am I wrong (I hope)???
-- LuisR
--------
Luis Alonso Ramos
Chihuahua, Mexico
www.luisalonsoramos.com
|
|
|
|
|
I've made a research on the subject and found that there's no definite answer. Unisys holds the rights to the LZW algorythm used in GIF so you cannot implement your own decoder or use someone else's without paying to Unisys (that includes Microsoft development tools like Visual Basic). But in the case of CPictureEx, there's no custom LZW-decoder - it uses the WinAPI function! (OleLoadPicture) So the question is whether we can use WinAPI functions and not pay to anyone (Microsoft has an agreement with Unisys btw - see Q193543). I don't know the answer and I doubt anyone does (save Unisys or Microsoft lawyers).
|
|
|
|
|
from http://www.unisys.com/unisys/lzw/ :
"Microsoft Corporation obtained a license under the above Unisys LZW patents in September, 1996. Microsoft's license does NOT extend to software developers or third parties who use Microsoft
toolkit, language, development or operating system products to provide GIF read/write and/or any other LZW capabilities in their own products (e.g., by way of DLLs and APIs). The complete statement by Microsoft can be found at Microsoft's
developer-oriented Web site at http://www.microsoft.com/DEVONLY/Unisys.htm. Software developers and third parties who wish to include Microsoft toolkit, language, development or operating system products in their own products for providing GIF or any other LZW capability should contact Unisys for a license as instructed below. Other forms of LZW are, for example, TIFF-LZW, PDF and Postscript-2.
"
i have talked to Unisys about this (how come MS gets to distribute LZW code, but i can't?). the answer is simple - MS paid a lot of money to be able to do so.
-c
------------------------------
Smaller Animals Software, Inc.
http://www.smalleranimals.com
|
|
|
|
|
you are correct.
http://www.unisys.com/unisys/lzw/
-c
------------------------------
Smaller Animals Software, Inc.
http://www.smalleranimals.com
|
|
|
|
|
Chris ,
Do you know if this has been tested in court ?
Regardz
Colin J Davies
|
|
|
|
|
What has been tested in court?
They hold the patents and for the most part can do anything they damn well please.
If an application is using LZW without permission, then at any point Unisys can come down on them. Under US law, they are not required to take action against all improper use of the patent.
Tim Smith
Descartes Systems Sciences, Inc.
|
|
|
|
|
>> What has been tested in court?
>> They hold the patents and for the most part can do anything they damn well please. <<
It's not that simple. First of all, just because a patent has ben granted, doesn't mean it can't be challenged. To be patented, an invention must be original and "not obvious" to someone trained inthe field. UniSys's patent in fact only covers the improvements made by Mr. Welsh on the algorithm previously invented by Mr Lev & Mr Zimpl (not certain about those name)
Now, there are many ways one could compress a file, but only compressed, there's only one way to restore it to it's original contents. Hence, it could be argued (And I think successfully), that a LZW *compressor* is patentable, but a *decompressor* is not.
However, challenging the patent would entail a very expensive lawsuit, which would require instructing a jury a obscure techinical matter, and hoping they would understand. So far, everyone decided that it would be cheaper to pay them off.
Truth,
James
|
|
|
|
|
as Tim noted, since they have the patent (in the US and some other countries), it's pretty much beyond question.
i haven't heard of anyone actually going to court. but i'm fairly sure i would've heard about it on Slashdot or on the graphics newsgroups, if it did happen. i do know they've sent lawyers after some developers; for example, there is a set of freeware image tools for *nix called "GD". the authors got into some hot water a couple of years ago for distributing GIF/LZW code - primarily because the tools are intended for server-side processing and Unisys is really uptight about unlicensed LZW on servers; they actually have (had?) a program where server owners could pay Unisys a yearly fee, to exempt them from any possible penalties in case they're caught using GIF software that doesn't have a Unisys license. GD ended up dropping GIF for PNG.
luckily their patent runs out in June 2003.
-c
------------------------------
Smaller Animals Software, Inc.
http://www.smalleranimals.com
|
|
|
|
|
>> luckily their patent runs out in June 2003.
Free-Quoted (I think it was on UNISYS website, but I'm not sure)
"the basic patent on LZW will run out in... Patents on some variants will run longer". With GIF being a variant, we'll see.....
|
|
|
|
|
"With GIF being a variant, we'll see....."
UniSys does NOT own the patent on the GIF format, only the LZW algorithm. THe GIF format was designed by CompuServe, which, as far as I know, have not attempted to enforce patent protection on it.
Truth,
James
|
|
|
|
|
The statement I remember was "original LZW patent expires in foo, whereas patents on various variants run much longer", and Now GIF uses an LZW variant.
|
|
|
|
|
|
I've also been down this path - it pretty well caused us to abandon a project - we were involved in advertising eg using an app that would pay for itself by showing small adverts (a common practice - in the naive internet boom when advertisers would pay per impression) - however most advertisers only had GIFs or animated GIFs and so we contacted UNISYS over the licence and they wanted 1 percent of revenues (not profit but revenue) since the app was free and all we got was advertising revenue and we were cutting it close (1% would tip us over) - luckily we abandoned the project just before the internet boom went splat and so were not a casualty more of a bystander who just watched the guy in front of him get hit by a bus
|
|
|
|
|
There is a website dedicated to fighting this type of thing, called the League for Programming Freedom. They are against intellectual patent laws that allow people like Unisys to patent LZW, Amazon to patent "One Click Purchasing" and such. Obviously, stealing the code to encrypt/decrypt LZW would be illegal (a copyright issue), but it should be legal for me to devise my own method of encrypting or decrypting any algorithm.
Unfortunately, due to the way the legal system works, that is not the case. This is why Unisys can sue people (And they do. Consistently - Even freeware programmers) for using "their" compression routine.
Did you know that XOR is patented? You can read more about it at the League for Programming Freedom at: http://lpf.ai.mit.edu/
-Mike Stevenson
CoderX@liquidmirror.com
Owner, Liquid Mirror Software (http://www.liquidmirror.com)
Owner, Shareware Junction (http://www.sharewarejunction.com)
Owner, Internet Shopping Spree (http://www.internetshoppingspree.com/)
|
|
|
|
|
Obviously, stealing the code to encrypt/decrypt LZW would be illegal (a copyright issue), but it should be legal for me to devise my own method of encrypting or decrypting any algorithm.
a couple of points...
first, IANAL (I Am Not A Lawyer)
second, it's a patent issue, not a copyright issue. they're very different.
third, you can study, share, examine, tweak LZW reading/writing code all you want because that's exactly what a patent allows; it grants a limited monopoly on an invention in exchange for public disclosure of exactly how to duplicate it. that way people can learn from each other's inventions by reading the patent and saying "wow, cool!" - that's the public disclosure part. what you can't do is use Unisys's invention in your own stuff without permission - that's the monopoly part. the limited part is that patents are time limited. 20 years for the LZW patent.
the thing about the LZW patent, like all good patents, is that Unisys was smart enough to describe it in such a way that the only real way to do LZW de/encoding is by doing exactly what their patent describes. the fact that nobody has found a good way around the patent in the 18 years it's been out is proof of that.
it's a shame Compuserve chose LZW for GIF.
-c
------------------------------
Smaller Animals Software, Inc.
http://www.smalleranimals.com
|
|
|
|
|
No, it's a shame that Unisys, years after GIF was widely established suddenly "discovered" they have a patent on it.
It's a shame that Unisys first announced "We won't go after freeware developers", and now they do
It's a shame that "without permission" means "without paying".
It's a shame that Unisys requests fees that are not affordable for small shops.
It's a shame that they are still in business.
---------------------
Don't get me wrong. I'm not against patents. The company I work for could drop dead without. However, if you're to stupid to *know* yu have a patent, you don't deserve it.
Peter
|
|
|
|
|
WHAAAAA WHAAAAA
They have something I want!!!!!
WHAAAAA WHAAAAA
I should be able to take it from them!!!!
WHAAAAA WHAAAAA
....
yeah....
right....
Tim Smith
Descartes Systems Sciences, Inc.
|
|
|
|
|
|