/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % CCCC L IIIII PPPP BBBB OOO AAA RRRR DDDD % % C L I P P B B O O A A R R D D % % C L I PPP BBBB O O AAAAA RRRR D D % % C L I P B B O O A A R R D D % % CCCC LLLLL IIIII P BBBB OOO A A R R DDDD % % % % % % Read/Write Windows Clipboard. % % % % Software Design % % Leonard Rosenthol % % May 2002 % % % % % % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % https://imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % */ /* Include declarations. */ #include "MagickCore/studio.h" #if defined(MAGICKCORE_WINGDI32_DELEGATE) # if defined(__CYGWIN__) # include # else /* All MinGW needs ... */ # include "MagickCore/nt-base-private.h" # include # endif #endif #include "MagickCore/blob.h" #include "MagickCore/blob-private.h" #include "MagickCore/cache.h" #include "MagickCore/exception.h" #include "MagickCore/exception-private.h" #include "MagickCore/image.h" #include "MagickCore/image-private.h" #include "MagickCore/list.h" #include "MagickCore/magick.h" #include "MagickCore/memory_.h" #include "MagickCore/nt-feature.h" #include "MagickCore/pixel-accessor.h" #include "MagickCore/quantum-private.h" #include "MagickCore/static.h" #include "MagickCore/string_.h" #include "MagickCore/module.h" #define BMP_HEADER_SIZE 14 /* Forward declarations. */ #if defined(MAGICKCORE_WINGDI32_DELEGATE) static MagickBooleanType WriteCLIPBOARDImage(const ImageInfo *,Image *,ExceptionInfo *); #endif /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d C L I P B O A R D I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadCLIPBOARDImage() reads an image from the system clipboard and returns % it. It allocates the memory necessary for the new Image structure and % returns a pointer to the new image. % % The format of the ReadCLIPBOARDImage method is: % % Image *ReadCLIPBOARDImage(const ImageInfo *image_info, % ExceptionInfo exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ #if defined(MAGICKCORE_WINGDI32_DELEGATE) static Image *ReadCLIPBOARDImage(const ImageInfo *image_info, ExceptionInfo *exception) { unsigned char *p; HANDLE clip_handle; Image *image; ImageInfo *read_info; LPVOID clip_mem; size_t clip_size, total_size; unsigned char offset; void *clip_data; assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); image=AcquireImage(image_info,exception); if (!IsClipboardFormatAvailable(CF_DIB) && !IsClipboardFormatAvailable(CF_DIBV5)) ThrowReaderException(CoderError,"NoBitmapOnClipboard"); if (!OpenClipboard(NULL)) ThrowReaderException(CoderError,"UnableToReadImageData"); clip_handle=GetClipboardData(CF_DIBV5); if (!clip_handle) clip_handle=GetClipboardData(CF_DIB); if ((clip_handle == NULL) || (clip_handle == INVALID_HANDLE_VALUE)) { CloseClipboard(); ThrowReaderException(CoderError,"UnableToReadImageData"); } clip_size=(size_t) GlobalSize(clip_handle); total_size=clip_size+BMP_HEADER_SIZE; clip_data=AcquireMagickMemory(total_size); if (clip_data == (void *) NULL) { CloseClipboard(); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } clip_mem=GlobalLock(clip_handle); if (clip_mem == (LPVOID) NULL) { CloseClipboard(); clip_data=RelinquishMagickMemory(clip_data); ThrowReaderException(CoderError,"UnableToReadImageData"); } p=(unsigned char *) clip_data; p+=BMP_HEADER_SIZE; (void) memcpy(p,clip_mem,clip_size); (void) GlobalUnlock(clip_mem); (void) CloseClipboard(); memset(clip_data,0,BMP_HEADER_SIZE); offset=p[0]; if ((p[0] == 40) && (p[16] == BI_BITFIELDS)) offset+=12; else { unsigned int image_size; image_size=(unsigned int) p[20]; image_size|=(unsigned int) p[21] << 8; image_size|=(unsigned int) p[22] << 16; image_size|=(unsigned int) p[23] << 24; /* Hack for chrome where the offset seems to be incorrect */ if (clip_size - offset - image_size == 12) offset+=12; } offset+=BMP_HEADER_SIZE; p-=BMP_HEADER_SIZE; p[0]='B'; p[1]='M'; p[2]=(unsigned char) total_size; p[3]=(unsigned char) (total_size >> 8); p[4]=(unsigned char) (total_size >> 16); p[5]=(unsigned char) (total_size >> 24); p[10]=offset; read_info=CloneImageInfo(image_info); (void) CopyMagickString(read_info->magick,"BMP",MagickPathExtent); image=BlobToImage(read_info,clip_data,total_size,exception); read_info=DestroyImageInfo(read_info); clip_data=RelinquishMagickMemory(clip_data); return(image); } #endif /* MAGICKCORE_WINGDI32_DELEGATE */ /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e g i s t e r C L I P B O A R D I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % RegisterCLIPBOARDImage() adds attributes for the clipboard "image format" to % the list of supported formats. The attributes include the image format % tag, a method to read and/or write the format, whether the format % supports the saving of more than one frame to the same file or blob, % whether the format supports native in-memory I/O, and a brief % description of the format. % % The format of the RegisterCLIPBOARDImage method is: % % size_t RegisterCLIPBOARDImage(void) % */ ModuleExport size_t RegisterCLIPBOARDImage(void) { MagickInfo *entry; entry=AcquireMagickInfo("CLIPBOARD","CLIPBOARD","The system clipboard"); #if defined(MAGICKCORE_WINGDI32_DELEGATE) entry->decoder=(DecodeImageHandler *) ReadCLIPBOARDImage; entry->encoder=(EncodeImageHandler *) WriteCLIPBOARDImage; #endif entry->flags^=CoderAdjoinFlag; entry->format_type=ImplicitFormatType; (void) RegisterMagickInfo(entry); return(MagickImageCoderSignature); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % U n r e g i s t e r C L I P B O A R D I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % UnregisterCLIPBOARDImage() removes format registrations made by the % RGB module from the list of supported formats. % % The format of the UnregisterCLIPBOARDImage method is: % % UnregisterCLIPBOARDImage(void) % */ ModuleExport void UnregisterCLIPBOARDImage(void) { (void) UnregisterMagickInfo("CLIPBOARD"); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e C L I P B O A R D I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteCLIPBOARDImage() writes an image to the system clipboard. % % The format of the WriteCLIPBOARDImage method is: % % MagickBooleanType WriteCLIPBOARDImage(const ImageInfo *image_info, % Image *image,ExceptionInfo *exception) % % A description of each parameter follows. % % o image_info: the image info. % % o image: The image. % % o exception: return any errors or warnings in this structure. % */ #if defined(MAGICKCORE_WINGDI32_DELEGATE) static MagickBooleanType WriteCLIPBOARDImage(const ImageInfo *image_info, Image *image,ExceptionInfo *exception) { HANDLE clip_handle; ImageInfo *write_info; LPVOID clip_mem; size_t length; unsigned char *p; void *clip_data; assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); assert(image != (Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) ThrowWriterException(CoderError,"UnableToWriteImageData"); write_info=CloneImageInfo(image_info); if (image->alpha_trait == UndefinedPixelTrait) (void) CopyMagickString(write_info->magick,"BMP3",MagickPathExtent); else (void) CopyMagickString(write_info->magick,"BMP",MagickPathExtent); clip_data=ImageToBlob(write_info,image,&length,exception); write_info=DestroyImageInfo(write_info); if (clip_data == (void *) NULL) ThrowWriterException(CoderError,"UnableToWriteImageData"); clip_handle=(HANDLE) GlobalAlloc(GMEM_MOVEABLE,length-BMP_HEADER_SIZE); if (clip_handle == (HANDLE) NULL) { clip_data=RelinquishMagickMemory(clip_data); ThrowWriterException(CoderError,"UnableToWriteImageData"); } clip_mem=GlobalLock(clip_handle); if (clip_mem == (LPVOID) NULL) { (void) GlobalFree((HGLOBAL) clip_handle); clip_data=RelinquishMagickMemory(clip_data); ThrowWriterException(CoderError,"UnableToWriteImageData"); } p=(unsigned char *) clip_data; p+=BMP_HEADER_SIZE; (void) memcpy(clip_mem,p,length-BMP_HEADER_SIZE); (void) GlobalUnlock(clip_mem); clip_data=RelinquishMagickMemory(clip_data); if (!OpenClipboard(NULL)) { (void) GlobalFree((HGLOBAL) clip_handle); ThrowWriterException(CoderError,"UnableToWriteImageData"); } (void) EmptyClipboard(); if (image->alpha_trait == UndefinedPixelTrait) SetClipboardData(CF_DIB,clip_handle); else SetClipboardData(CF_DIBV5,clip_handle); (void) CloseClipboard(); return(MagickTrue); } #endif /* MAGICKCORE_WINGDI32_DELEGATE */