/* Implementation of GUI terminal on the Microsoft Windows API. Copyright (C) 1989, 1993-2020 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include #include "lisp.h" #include "dispextern.h" #define COBJMACROS #include #include #include #include #include "w32term.h" #include "frame.h" #include "coding.h" static int gdiplus_initialized_p() { static int gdip_initialized = 0; static ULONG_PTR token; static GdiplusStartupInput input; static GdiplusStartupOutput output; GpStatus status; if (gdip_initialized < 0) { return 0; } else if (gdip_initialized) { return 1; } else { input.GdiplusVersion = 1; input.DebugEventCallback = NULL; input.SuppressBackgroundThread = FALSE; input.SuppressExternalCodecs = FALSE; status = GdiplusStartup(&token, &input, &output); if (status == Ok) { gdip_initialized = 1; return 1; } else { gdip_initialized = -1; return 0; } } return 1; } static float w32_frame_delay(GpBitmap *pBitmap, int frame) { UINT size; PropertyItem *propertyItem; float delay = 0.0; // Assume that the image has a property item of type PropertyItemEquipMake. // Get the size of that property item. GdipGetPropertyItemSize(pBitmap, PropertyTagFrameDelay, &size); // Allocate a buffer to receive the property item. propertyItem = (PropertyItem*)malloc(size); if (propertyItem != NULL) { // Get the property item. GdipGetPropertyItem(pBitmap, PropertyTagFrameDelay, size, propertyItem); delay = ((float)propertyItem[frame].length) / 100; if (delay == 0) { /* In GIF files, unfortunately, delay is only specified for the first frame */ delay = ((float)propertyItem[0].length) / 100; } // Free space free(propertyItem); } return delay; } static UINT w32_select_active_frame(GpBitmap *pBitmap, int frame, int *nframes, float *delay) { UINT count, frameCount; GUID pDimensionIDs[1]; GpStatus status = Ok; status = GdipImageGetFrameDimensionsCount(pBitmap, &count); frameCount = *nframes = 0; *delay = 0.0; if (count) { status = GdipImageGetFrameDimensionsList(pBitmap, pDimensionIDs, 1); status = GdipImageGetFrameCount(pBitmap, &pDimensionIDs[0], &frameCount); fprintf(stderr, "FrameCount: %d\n", (int)frameCount); fprintf(stderr, " index: %d\n", frame); if ((status == Ok) && (frameCount > 1)) { if (frame < 0 || frame >= frameCount) { status = GenericError; } else { status = GdipImageSelectActiveFrame(pBitmap, &pDimensionIDs[0], frame); *delay = w32_frame_delay(pBitmap, frame); *nframes = frameCount; } } } return status; } static ARGB w32_image_bg_color(struct frame *f, struct image *img) { /* png_color_16 *image_bg; */ Lisp_Object specified_bg = Fplist_get (XCDR (img->spec), QCbackground); Emacs_Color color; /* If the user specified a color, try to use it; if not, use the current frame background, ignoring any default background color set by the image. */ if (STRINGP (specified_bg) ? FRAME_TERMINAL (f)->defined_color_hook (f, SSDATA (specified_bg), &color, false, false) : (FRAME_TERMINAL (f)->query_frame_background_color (f, &color), true)) /* The user specified `:background', use that. */ { DWORD red = (((DWORD) color.red) & 0xff00) << 8; DWORD green = ((DWORD) color.green) & 0xff00; DWORD blue = ((DWORD) color.blue) >> 8; return red | green | blue; } return ((DWORD) 0xff000000); } int w32_load_image (struct frame *f, struct image *img, Lisp_Object spec_file, Lisp_Object spec_data) { Emacs_Pixmap pixmap; GpStatus status = GenericError; GpBitmap *pBitmap; wchar_t filename[MAX_PATH]; ARGB bg_color; Lisp_Object lisp_index, metadata; unsigned int index, nframes; float delay; eassert (valid_image_p (img->spec)); if (!gdiplus_initialized_p ()) { return 0; } if (STRINGP (spec_file)) { filename_to_utf16 (SSDATA (spec_file) , filename); status = GdipCreateBitmapFromFile (filename, &pBitmap); } else if (STRINGP (spec_data)) { IStream *pStream = SHCreateMemStream ((BYTE *) SSDATA (spec_data), SBYTES (spec_data)); if (pStream != NULL) { status = GdipCreateBitmapFromStream (pStream, &pBitmap); IStream_Release(pStream); } } metadata = Qnil; if (status == Ok) { /* In multiframe pictures, select the first one */ lisp_index = Fplist_get (XCDR (img->spec), QCindex); index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0; status = w32_select_active_frame (pBitmap, index, &nframes, &delay); if ((status == Ok)) { if (nframes > 1) metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata)); if (delay) metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata)); } } if (status == Ok) { bg_color = w32_image_bg_color(f, img); status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color); if (status == Ok) { UINT width, height; GdipGetImageWidth (pBitmap, &width); GdipGetImageHeight (pBitmap, &height); img->width = width; img->height = height; img->pixmap = pixmap; img->lisp_data = metadata; } GdipDisposeImage (pBitmap); } if (status != Ok) { add_to_log ("Unable to load image %s", img->spec); return 0; } return 1; }