Today, I am in a bad mood. The reason is that I spent 5 yuan to buy a scratch color and gave it a 100 shopping spree. I feel happy. Now, let's get started. We will not talk about the introduction of GDI + here. In short, it is much more convenient than GDI. For example, GDI only supports BMP format bitmap, for other formats such as JPG, PNG, GIF ..... it is very difficult to use, but it is supported by GDI +, and it is very easy to use, such as placing a jpg image:
Image image(L"Texture1.jpg");graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());
Of course, you also need to construct a graphics object, which is also very convenient:
Graphics graphics(hdc);
Microsoft Windows GDI + contains about 40 classes, 50 enumerations, and 6 structs. At the same time, a few functions do not belong to any class. The graphics class is the core of the entire GDI + interface. It is used to draw lines, curves, graphs, images, and texts.
Most classes andGraphicsClass. For example, the graphics: drawline method accepts a vertex and passes it to a pen object, which stores the attributes of the line to be drawn (color, width, dotted line type, and others ). Graphics: The fillrectangle method accepts a vertex and transmits it to the lineargradientbrush object.GraphicsObject To implement gradient filling of the rectangle. Font and stringformat objectsGraphicsThe method by which the object draws text. The matrix object is used to store and generateGraphicsThe world transformation matrix of an object for rotating, scaling, and turning an image.
If you want to know more specifically, go to your mother and Google. What impressed me for the first time when I came into contact with GDI + was his linear gradient and path gradient, and image rotation and image translation, the pictures made with these images are very nice and easy to operate ....... It's not just my style. If you get started with it, you will understand it.
Speaking of supporting GIF, I quickly tested it and changed the JPG in the above Code to gif. If GIF is static, it fully meets the requirements, if it is dynamic, the running results will be a little disappointing. The reality is static. The accuracy is the first frame of the GIF image. How can I load the dynamic GIF, the first thing that comes to mind is analyzing the GIF format. You can find a lot of information on the Internet, but it is quite difficult to look at it. After reading the analysis, we know that GIF actually consists of many Song frames, we can display the results one by one, so that the overall result is a qualified result.
First, determine the number of frames in a GIF. The following APIs are used:
Image *image=new Image(L"123.gif"); UINT count=0; count=image->GetFrameDimensionsCount(); GUID *pDimensionIDs=(GUID*)new GUID[count]; image->GetFrameDimensionsList(pDimensionIDs,count); WCHAR strGuid[39]; StringFromGUID2(pDimensionIDs[0],strGuid,39); UINT frameCount=image->GetFrameCount(&pDimensionIDs[0]); delete []pDimensionIDs;
After obtaining the number of frames, we can determine whether the GIF is dynamic based on the number. If the number is greater than 1, we can determine the frame time after the number is determined, latency.
// Assume that the image has an attribute entry propertyitemequipmake. // obtain the size of this entry. int nsize = getpropertyitemsize (propertytagframedelay); // allocate space for Attribute entries. m_ppropertyitem = (propertyitem *) malloc (nsize); getpropertyitem (propertytagframedelay, nsize, m_ppropertyitem); m_ppropertyitem-> value is a long integer array, and each long integer represents the delay of each frame. Because different properties are obtained, getpropertyitem will get objects of different sizes. Therefore, the size of the objects to be obtained by the user will open up memory related to the deletion of getpropertyitem. The object size is obtained through getpropertyitemsize, and its parameters are the attribute entries you are interested in. Once the number and latency of frames are obtained, a thread can be generated to call drawframegif () for display.
At first, I didn't use threads. I thought it was difficult to control threads (I had few applications on threads). Instead, I wrote a separate function and put it in wm_paint, this is probably the case:
void showimage(HDC hdc){Image *image=new Image(L"123.gif"); UINT count=0; count=image->GetFrameDimensionsCount(); GUID *pDimensionIDs=(GUID*)new GUID[count]; image->GetFrameDimensionsList(pDimensionIDs,count); WCHAR strGuid[39]; StringFromGUID2(pDimensionIDs[0],strGuid,39); UINT frameCount=image->GetFrameCount(&pDimensionIDs[0]); delete []pDimensionIDs; int size=image->GetPropertyItemSize(PropertyTagFrameDelay); PropertyItem* pItem=NULL; pItem=(PropertyItem*)malloc(size); image->GetPropertyItem(PropertyTagFrameDelay,size,pItem); UINT fcount=0; GUID Guid=FrameDimensionTime; while(true) { Graphics graphics(hdc); graphics.DrawImage(image,0,0,image->GetWidth(),image->GetHeight()); image->SelectActiveFrame(&Guid,fcount++); if(fcount==frameCount) fcount=0; long lPause=((long*)pItem->value)[fcount]*10; Sleep(lPause); }}
The wm_paint message is displayed, but the dynamic GIF is displayed during running. However, when the focus of the program window is lost and the picture is repainted, the animation will not be moved. The same is true for the minimum maximization, it may be the endless loop. At this time, I thought of multiple threads to complete it. So I changed the code, which should be like this:
void __cdecl showimage(LPVOID){ HDC hdc=GetDC(g_hWnd); Image *image=new Image(L"123.gif"); UINT count=0; count=image->GetFrameDimensionsCount(); GUID *pDimensionIDs=(GUID*)new GUID[count]; image->GetFrameDimensionsList(pDimensionIDs,count); WCHAR strGuid[39]; StringFromGUID2(pDimensionIDs[0],strGuid,39); UINT frameCount=image->GetFrameCount(&pDimensionIDs[0]); delete []pDimensionIDs; int size=image->GetPropertyItemSize(PropertyTagFrameDelay); PropertyItem* pItem=NULL; pItem=(PropertyItem*)malloc(size); image->GetPropertyItem(PropertyTagFrameDelay,size,pItem); UINT fcount=0; GUID Guid=FrameDimensionTime; while(true) { Graphics graphics(hdc); graphics.DrawImage(image,0,0,image->GetWidth(),image->GetHeight()); image->SelectActiveFrame(&Guid,fcount++); if(fcount==frameCount) fcount=0; long lPause=((long*)pItem->value)[fcount]*10; Sleep(lPause); } ReleaseDC(g_hWnd,hdc);}
case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... RECT rt; GetClientRect(hWnd, &rt); _beginthread(showimage,0,0); //showimage(hdc); EndPaint(hWnd, &ps); break;
The explicit display is a little different from the original image. In short, it is not ideal. The reason is roughly checked. It may be that if the thread has not been executed or played, the endpaint (hwnd, & PS );
Finally, I talked to netizens about the timer concept. I thought it was true that the timer could be done. The idea was as follows:
Enable a timer. The time interval from the current GIF frame to the next frame is used as the timer interval (minimum 100 ms ). (The timer is used only once ). Every time the timer arrives. Set the activity frame to the next frame, and then trigger the window re-painting.
The rest. You only need to draw the current GIF frame in wm_paint.
General process:
1. Set the frame interval and enable the timer.
2. timer. Kill the timer, select the next frame, and then take the frame interval.
3. Trigger window re-painting.
According to this idea, the loading of GIF dynamic images is finally perfect. The main code is roughly as follows:
// Define two IDs # define timer_fir 1 # define timer_sec 2 // core work case wm_create: settimer (hwnd, timer_fir, 0, null); break; Case wm_timer: {Switch (wparam) {Case timer_fir: {HDC = getdc (hwnd); image = new image (L "123.gif"); Count = 0; Count = image-> getframedimensionscount (); pdimensionids = (guid *) New guid [count]; image-> getframedimensionslist (pdimensionids, count); stringfromguid2 (pdimensionids [0], strguid, 39 ); framecount = image-> getframecount (& pdimensionids [0]); Delete [] pdimensionids; size = image-> getpropertyitemsize (propertytagframedelay); // propertyitem * pitem = NULL; // pitem = (propertyitem *) malloc (size); pitem = (propertyitem *) New propertyitem [size]; image-> getpropertyitem (propertytagframedelay, size, pitem ); fcount = 0; guid = framedimensiontime; graphics (HDC); graphics. drawimage (image, 0, 0); image-> selectactiveframe (& guid, fcount ++); If (fcount = framecount) fcount = 0; lpause = (long *) pitem-> value) [fcount] * 10; // releasedc (hwnd, HDC); killtimer (hwnd, timer_fir); settimer (hwnd, timer_sec, lpause, null ); invalidaterect (hwnd, null, false); break;} case timer_sec: {image-> selectactiveframe (& guid, fcount ++); If (fcount = framecount) fcount = 0; lpause = (long *) pitem-> value) [fcount] * 10; killtimer (hwnd, timer_sec); settimer (hwnd, timer_sec, lpause, null); invalidaterect (hwnd, null, false );}}}
I mainly want to share my thoughts on how to solve this problem, so that we will not be able to avoid further detours.
Paste a run:
The complete project has been uploaded to the csdn resource area, but I do not know why I still cannot find the address. I will attach a nearby one later (wait for the csdn message ). Finally, you are welcome to exchange and learn.