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