1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% X X PPPP SSSSS % 7% X X P P SS % 8% X PPPP SSS % 9% X X P SS % 10% X X P SSSSS % 11% % 12% % 13% Read/Write Microsoft XML Paper Specification Format % 14% % 15% Software Design % 16% Cristy % 17% January 2008 % 18% % 19% % 20% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/blob-private.h" 46#include "MagickCore/color.h" 47#include "MagickCore/color-private.h" 48#include "MagickCore/colorspace.h" 49#include "MagickCore/constitute.h" 50#include "MagickCore/delegate.h" 51#include "MagickCore/draw.h" 52#include "MagickCore/exception.h" 53#include "MagickCore/exception-private.h" 54#include "MagickCore/geometry.h" 55#include "MagickCore/image.h" 56#include "MagickCore/image-private.h" 57#include "MagickCore/list.h" 58#include "MagickCore/magick.h" 59#include "MagickCore/memory_.h" 60#include "MagickCore/monitor.h" 61#include "MagickCore/monitor-private.h" 62#include "MagickCore/option.h" 63#include "MagickCore/profile.h" 64#include "MagickCore/property.h" 65#include "MagickCore/resource_.h" 66#include "MagickCore/quantum-private.h" 67#include "MagickCore/static.h" 68#include "MagickCore/string_.h" 69#include "MagickCore/module.h" 70#include "MagickCore/token.h" 71#include "MagickCore/transform.h" 72#include "MagickCore/utility.h" 73 74/* 75%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 76% % 77% % 78% % 79% R e a d X P S I m a g e % 80% % 81% % 82% % 83%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 84% 85% ReadXPSImage() reads a Printer Control Language image file and returns it. 86% It allocates the memory necessary for the new Image structure and returns a 87% pointer to the new image. 88% 89% The format of the ReadXPSImage method is: 90% 91% Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception) 92% 93% A description of each parameter follows: 94% 95% o image_info: the image info. 96% 97% o exception: return any errors or warnings in this structure. 98% 99*/ 100static Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception) 101{ 102#define CropBox "CropBox" 103#define DeviceCMYK "DeviceCMYK" 104#define MediaBox "MediaBox" 105#define RenderXPSText " Rendering XPS... " 106 107 char 108 command[MagickPathExtent], 109 *density, 110 filename[MagickPathExtent], 111 geometry[MagickPathExtent], 112 *options, 113 input_filename[MagickPathExtent]; 114 115 const DelegateInfo 116 *delegate_info; 117 118 Image 119 *image, 120 *next_image; 121 122 ImageInfo 123 *read_info; 124 125 MagickBooleanType 126 cmyk, 127 status; 128 129 PointInfo 130 delta; 131 132 RectangleInfo 133 bounding_box, 134 page; 135 136 register char 137 *p; 138 139 register ssize_t 140 c; 141 142 SegmentInfo 143 bounds; 144 145 size_t 146 height, 147 width; 148 149 ssize_t 150 count; 151 152 assert(image_info != (const ImageInfo *) NULL); 153 assert(image_info->signature == MagickCoreSignature); 154 if (image_info->debug != MagickFalse) 155 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 156 image_info->filename); 157 assert(exception != (ExceptionInfo *) NULL); 158 assert(exception->signature == MagickCoreSignature); 159 /* 160 Open image file. 161 */ 162 image=AcquireImage(image_info,exception); 163 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 164 if (status == MagickFalse) 165 { 166 image=DestroyImageList(image); 167 return((Image *) NULL); 168 } 169 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename); 170 if (status == MagickFalse) 171 { 172 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", 173 image_info->filename); 174 image=DestroyImageList(image); 175 return((Image *) NULL); 176 } 177 /* 178 Set the page density. 179 */ 180 delta.x=DefaultResolution; 181 delta.y=DefaultResolution; 182 if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0)) 183 { 184 GeometryInfo 185 geometry_info; 186 187 MagickStatusType 188 flags; 189 190 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 191 image->resolution.x=geometry_info.rho; 192 image->resolution.y=geometry_info.sigma; 193 if ((flags & SigmaValue) == 0) 194 image->resolution.y=image->resolution.x; 195 } 196 /* 197 Determine page geometry from the XPS media box. 198 */ 199 cmyk=image->colorspace == CMYKColorspace ? MagickTrue : MagickFalse; 200 count=0; 201 (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box)); 202 (void) ResetMagickMemory(&bounds,0,sizeof(bounds)); 203 (void) ResetMagickMemory(&page,0,sizeof(page)); 204 (void) ResetMagickMemory(command,0,sizeof(command)); 205 p=command; 206 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image)) 207 { 208 if (image_info->page != (char *) NULL) 209 continue; 210 /* 211 Note XPS elements. 212 */ 213 *p++=(char) c; 214 if ((c != (int) '/') && (c != '\n') && 215 ((size_t) (p-command) < (MagickPathExtent-1))) 216 continue; 217 *p='\0'; 218 p=command; 219 /* 220 Is this a CMYK document? 221 */ 222 if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0) 223 cmyk=MagickTrue; 224 if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0) 225 { 226 /* 227 Note region defined by crop box. 228 */ 229 count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf", 230 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 231 if (count != 4) 232 count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf", 233 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 234 } 235 if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0) 236 { 237 /* 238 Note region defined by media box. 239 */ 240 count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf", 241 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 242 if (count != 4) 243 count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf", 244 &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2); 245 } 246 if (count != 4) 247 continue; 248 /* 249 Set XPS render geometry. 250 */ 251 width=(size_t) (floor(bounds.x2+0.5)-ceil(bounds.x1-0.5)); 252 height=(size_t) (floor(bounds.y2+0.5)-ceil(bounds.y1-0.5)); 253 if (width > page.width) 254 page.width=width; 255 if (height > page.height) 256 page.height=height; 257 } 258 (void) CloseBlob(image); 259 /* 260 Render XPS with the GhostXPS delegate. 261 */ 262 if ((page.width == 0) || (page.height == 0)) 263 (void) ParseAbsoluteGeometry(PSPageGeometry,&page); 264 if (image_info->page != (char *) NULL) 265 (void) ParseAbsoluteGeometry(image_info->page,&page); 266 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g",(double) 267 page.width,(double) page.height); 268 if (image_info->monochrome != MagickFalse) 269 delegate_info=GetDelegateInfo("xps:mono",(char *) NULL,exception); 270 else 271 if (cmyk != MagickFalse) 272 delegate_info=GetDelegateInfo("xps:cmyk",(char *) NULL,exception); 273 else 274 delegate_info=GetDelegateInfo("xps:color",(char *) NULL,exception); 275 if (delegate_info == (const DelegateInfo *) NULL) 276 return((Image *) NULL); 277 density=AcquireString(""); 278 options=AcquireString(""); 279 (void) FormatLocaleString(density,MagickPathExtent,"%gx%g", 280 image->resolution.x,image->resolution.y); 281 if ((page.width == 0) || (page.height == 0)) 282 (void) ParseAbsoluteGeometry(PSPageGeometry,&page); 283 if (image_info->page != (char *) NULL) 284 (void) ParseAbsoluteGeometry(image_info->page,&page); 285 page.width=(size_t) floor(page.width*image->resolution.y/delta.x+0.5); 286 page.height=(size_t) floor(page.height*image->resolution.y/delta.y+0.5); 287 (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",(double) 288 page.width,(double) page.height); 289 image=DestroyImage(image); 290 read_info=CloneImageInfo(image_info); 291 *read_info->magick='\0'; 292 if (read_info->number_scenes != 0) 293 { 294 if (read_info->number_scenes != 1) 295 (void) FormatLocaleString(options,MagickPathExtent,"-dLastPage=%.20g", 296 (double) (read_info->scene+read_info->number_scenes)); 297 else 298 (void) FormatLocaleString(options,MagickPathExtent, 299 "-dFirstPage=%.20g -dLastPage=%.20g",(double) read_info->scene+1, 300 (double) (read_info->scene+read_info->number_scenes)); 301 read_info->number_scenes=0; 302 if (read_info->scenes != (char *) NULL) 303 *read_info->scenes='\0'; 304 } 305 (void) CopyMagickString(filename,read_info->filename,MagickPathExtent); 306 (void) AcquireUniqueFilename(read_info->filename); 307 (void) FormatLocaleString(command,MagickPathExtent, 308 GetDelegateCommands(delegate_info), 309 read_info->antialias != MagickFalse ? 4 : 1, 310 read_info->antialias != MagickFalse ? 4 : 1,density,options, 311 read_info->filename,input_filename); 312 options=DestroyString(options); 313 density=DestroyString(density); 314 status=ExternalDelegateCommand(MagickFalse,read_info->verbose,command, 315 (char *) NULL,exception) != 0 ? MagickTrue : MagickFalse; 316 image=ReadImage(read_info,exception); 317 (void) RelinquishUniqueFileResource(read_info->filename); 318 (void) RelinquishUniqueFileResource(input_filename); 319 read_info=DestroyImageInfo(read_info); 320 if (image == (Image *) NULL) 321 ThrowReaderException(DelegateError,"XPSDelegateFailed"); 322 if (LocaleCompare(image->magick,"BMP") == 0) 323 { 324 Image 325 *cmyk_image; 326 327 cmyk_image=ConsolidateCMYKImages(image,exception); 328 if (cmyk_image != (Image *) NULL) 329 { 330 image=DestroyImageList(image); 331 image=cmyk_image; 332 } 333 } 334 do 335 { 336 (void) CopyMagickString(image->filename,filename,MagickPathExtent); 337 image->page=page; 338 next_image=SyncNextImageInList(image); 339 if (next_image != (Image *) NULL) 340 image=next_image; 341 } while (next_image != (Image *) NULL); 342 return(GetFirstImageInList(image)); 343} 344 345/* 346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 347% % 348% % 349% % 350% R e g i s t e r X P S I m a g e % 351% % 352% % 353% % 354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 355% 356% RegisterXPSImage() adds attributes for the Microsoft XML Paper Specification 357% format to the list of supported formats. The attributes include the image 358% format tag, a method to read and/or write the format, whether the format 359% supports the saving of more than one frame to the same file or blob, 360% whether the format supports native in-memory I/O, and a brief 361% description of the format. 362% 363% The format of the RegisterXPSImage method is: 364% 365% size_t RegisterXPSImage(void) 366% 367*/ 368ModuleExport size_t RegisterXPSImage(void) 369{ 370 MagickInfo 371 *entry; 372 373 entry=AcquireMagickInfo("XPS","XPS","Microsoft XML Paper Specification"); 374 entry->decoder=(DecodeImageHandler *) ReadXPSImage; 375 entry->flags^=CoderAdjoinFlag; 376 entry->flags^=CoderBlobSupportFlag; 377 entry->flags^=CoderDecoderThreadSupportFlag; 378 entry->flags|=CoderSeekableStreamFlag; 379 (void) RegisterMagickInfo(entry); 380 return(MagickImageCoderSignature); 381} 382 383/* 384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 385% % 386% % 387% % 388% U n r e g i s t e r X P S I m a g e % 389% % 390% % 391% % 392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 393% 394% UnregisterXPSImage() removes format registrations made by the XPS module 395% from the list of supported formats. 396% 397% The format of the UnregisterXPSImage method is: 398% 399% UnregisterXPSImage(void) 400% 401*/ 402ModuleExport void UnregisterXPSImage(void) 403{ 404 (void) UnregisterMagickInfo("XPS"); 405} 406