xps.c revision 9950d57e1124b73f684fb5946e206994cefda628
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% John Cristy % 17% January 2008 % 18% % 19% % 20% Copyright 1999-2011 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/property.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/profile.h" 63#include "MagickCore/resource_.h" 64#include "MagickCore/quantum-private.h" 65#include "MagickCore/static.h" 66#include "MagickCore/string_.h" 67#include "MagickCore/module.h" 68#include "MagickCore/token.h" 69#include "MagickCore/transform.h" 70#include "MagickCore/utility.h" 71 72/* 73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 74% % 75% % 76% % 77% R e a d X P S I m a g e % 78% % 79% % 80% % 81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 82% 83% ReadXPSImage() reads a Printer Control Language image file and returns it. 84% It allocates the memory necessary for the new Image structure and returns a 85% pointer to the new image. 86% 87% The format of the ReadXPSImage method is: 88% 89% Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception) 90% 91% A description of each parameter follows: 92% 93% o image_info: the image info. 94% 95% o exception: return any errors or warnings in this structure. 96% 97*/ 98static Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception) 99{ 100#define CropBox "CropBox" 101#define DeviceCMYK "DeviceCMYK" 102#define MediaBox "MediaBox" 103#define RenderXPSText " Rendering XPS... " 104 105 char 106 command[MaxTextExtent], 107 density[MaxTextExtent], 108 filename[MaxTextExtent], 109 geometry[MaxTextExtent], 110 options[MaxTextExtent], 111 input_filename[MaxTextExtent]; 112 113 const DelegateInfo 114 *delegate_info; 115 116 Image 117 *image, 118 *next_image; 119 120 ImageInfo 121 *read_info; 122 123 MagickBooleanType 124 cmyk, 125 status; 126 127 PointInfo 128 delta; 129 130 RectangleInfo 131 bounding_box, 132 page; 133 134 register char 135 *p; 136 137 register ssize_t 138 c; 139 140 SegmentInfo 141 bounds; 142 143 size_t 144 height, 145 width; 146 147 ssize_t 148 count; 149 150 assert(image_info != (const ImageInfo *) NULL); 151 assert(image_info->signature == MagickSignature); 152 if (image_info->debug != MagickFalse) 153 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 154 image_info->filename); 155 assert(exception != (ExceptionInfo *) NULL); 156 assert(exception->signature == MagickSignature); 157 /* 158 Open image file. 159 */ 160 image=AcquireImage(image_info,exception); 161 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 162 if (status == MagickFalse) 163 { 164 image=DestroyImageList(image); 165 return((Image *) NULL); 166 } 167 status=AcquireUniqueSymbolicLink(image_info->filename,input_filename); 168 if (status == MagickFalse) 169 { 170 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", 171 image_info->filename); 172 image=DestroyImageList(image); 173 return((Image *) NULL); 174 } 175 /* 176 Set the page density. 177 */ 178 delta.x=DefaultResolution; 179 delta.y=DefaultResolution; 180 if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0)) 181 { 182 GeometryInfo 183 geometry_info; 184 185 MagickStatusType 186 flags; 187 188 flags=ParseGeometry(PSDensityGeometry,&geometry_info); 189 image->x_resolution=geometry_info.rho; 190 image->y_resolution=geometry_info.sigma; 191 if ((flags & SigmaValue) == 0) 192 image->y_resolution=image->x_resolution; 193 } 194 (void) FormatLocaleString(density,MaxTextExtent,"%gx%g", 195 image->x_resolution,image->y_resolution); 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) < (MaxTextExtent-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-bounds.x1+0.5); 252 height=(size_t) floor(bounds.y2-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,MaxTextExtent,"%.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 *options='\0'; 278 if ((page.width == 0) || (page.height == 0)) 279 (void) ParseAbsoluteGeometry(PSPageGeometry,&page); 280 if (image_info->page != (char *) NULL) 281 (void) ParseAbsoluteGeometry(image_info->page,&page); 282 page.width=(size_t) floor(page.width*image->y_resolution/delta.x+0.5); 283 page.height=(size_t) floor(page.height*image->y_resolution/delta.y+ 284 0.5); 285 (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double) 286 page.width,(double) page.height); 287 image=DestroyImage(image); 288 read_info=CloneImageInfo(image_info); 289 *read_info->magick='\0'; 290 if (read_info->number_scenes != 0) 291 { 292 if (read_info->number_scenes != 1) 293 (void) FormatLocaleString(options,MaxTextExtent,"-dLastPage=%.20g", 294 (double) (read_info->scene+read_info->number_scenes)); 295 else 296 (void) FormatLocaleString(options,MaxTextExtent, 297 "-dFirstPage=%.20g -dLastPage=%.20g",(double) read_info->scene+1, 298 (double) (read_info->scene+read_info->number_scenes)); 299 read_info->number_scenes=0; 300 if (read_info->scenes != (char *) NULL) 301 *read_info->scenes='\0'; 302 } 303 if (read_info->authenticate != (char *) NULL) 304 (void) FormatLocaleString(options+strlen(options),MaxTextExtent, 305 " -sXPSPassword=%s",read_info->authenticate); 306 (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); 307 (void) AcquireUniqueFilename(read_info->filename); 308 (void) FormatLocaleString(command,MaxTextExtent, 309 GetDelegateCommands(delegate_info), 310 read_info->antialias != MagickFalse ? 4 : 1, 311 read_info->antialias != MagickFalse ? 4 : 1,density,options, 312 read_info->filename,input_filename); 313 status=SystemCommand(MagickFalse,read_info->verbose,command,exception) != 0 ? 314 MagickTrue : MagickFalse; 315 image=ReadImage(read_info,exception); 316 (void) RelinquishUniqueFileResource(read_info->filename); 317 (void) RelinquishUniqueFileResource(input_filename); 318 read_info=DestroyImageInfo(read_info); 319 if (image == (Image *) NULL) 320 ThrowReaderException(DelegateError,"XPSDelegateFailed"); 321 if (LocaleCompare(image->magick,"BMP") == 0) 322 { 323 Image 324 *cmyk_image; 325 326 cmyk_image=ConsolidateCMYKImages(image,&image->exception); 327 if (cmyk_image != (Image *) NULL) 328 { 329 image=DestroyImageList(image); 330 image=cmyk_image; 331 } 332 } 333 do 334 { 335 (void) CopyMagickString(image->filename,filename,MaxTextExtent); 336 image->page=page; 337 next_image=SyncNextImageInList(image); 338 if (next_image != (Image *) NULL) 339 image=next_image; 340 } while (next_image != (Image *) NULL); 341 return(GetFirstImageInList(image)); 342} 343 344/* 345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 346% % 347% % 348% % 349% R e g i s t e r X P S I m a g e % 350% % 351% % 352% % 353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 354% 355% RegisterXPSImage() adds attributes for the Microsoft XML Paper Specification 356% format to the list of supported formats. The attributes include the image 357% format tag, a method to read and/or write the format, whether the format 358% supports the saving of more than one frame to the same file or blob, 359% whether the format supports native in-memory I/O, and a brief 360% description of the format. 361% 362% The format of the RegisterXPSImage method is: 363% 364% size_t RegisterXPSImage(void) 365% 366*/ 367ModuleExport size_t RegisterXPSImage(void) 368{ 369 MagickInfo 370 *entry; 371 372 entry=SetMagickInfo("XPS"); 373 entry->decoder=(DecodeImageHandler *) ReadXPSImage; 374 entry->adjoin=MagickFalse; 375 entry->blob_support=MagickFalse; 376 entry->seekable_stream=MagickTrue; 377 entry->thread_support=EncoderThreadSupport; 378 entry->description=ConstantString("Microsoft XML Paper Specification"); 379 entry->module=ConstantString("XPS"); 380 (void) RegisterMagickInfo(entry); 381 return(MagickImageCoderSignature); 382} 383 384/* 385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 386% % 387% % 388% % 389% U n r e g i s t e r X P S I m a g e % 390% % 391% % 392% % 393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 394% 395% UnregisterXPSImage() removes format registrations made by the XPS module 396% from the list of supported formats. 397% 398% The format of the UnregisterXPSImage method is: 399% 400% UnregisterXPSImage(void) 401% 402*/ 403ModuleExport void UnregisterXPSImage(void) 404{ 405 (void) UnregisterMagickInfo("XPS"); 406} 407