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