1 /* 2 * Copyright 2009 Alexander Curtis <alex@logicmill.com> 3 * This file is part of GEDmill - A family history website creator 4 * 5 * GEDmill is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * GEDmill is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with GEDmill. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 using System; 20 using System.Collections.Generic; 21 using System.Drawing; 22 using System.Drawing.Imaging; 23 using System.IO; 24 using System.Text; 25 using GDModel; 26 using GEDmill.Model; 27 using GKCore.Logging; 28 29 namespace GEDmill.HTML 30 { 31 /// <summary> 32 /// Base class providing general functionality required by all classes that create HTML pages. 33 /// </summary> 34 public abstract class Creator 35 { 36 private static readonly ILogger fLogger = LogManager.GetLogger(GMConfig.LOG_FILE, GMConfig.LOG_LEVEL, typeof(Creator).Name); 37 38 protected const string PageDescription = "GEDmill GEDCOM to HTML family history website"; 39 40 // The raw data that we are turning into a website. 41 protected GDMTree fTree; 42 43 // Pointer to the window showing the progress bar, so that web page creation progress can be shown to user. 44 private IProgressCallback fProgressWindow; 45 46 // The same multimedia file may be referenced multiple times. 47 // This hash prevents it being copied to the output directory more than once. 48 private static Dictionary<string, FilenameAndSize> fCopiedFiles = new Dictionary<string, FilenameAndSize>(); 49 50 // The sFilename for the Valid XHTML sticker image. 51 private string fW3CFile; 52 53 Creator(GDMTree tree, IProgressCallback progress, string w3cFile)54 protected Creator(GDMTree tree, IProgressCallback progress, string w3cFile) 55 { 56 fTree = tree; 57 fProgressWindow = progress; 58 fW3CFile = w3cFile; 59 } 60 61 // This clears the static list of all multimedia files copied to the output directory (and possibly renamed). ClearCopiedFilesList()62 public static void ClearCopiedFilesList() 63 { 64 fCopiedFiles.Clear(); 65 } 66 67 // Converts all HTML characters into their escaped versions 68 // Set hardSpace to false if you want to keep first space as breakable, true if you want all nbsp. 69 // TODO: Surely there is a .Net function to do this (WebUtility.HtmlEncode)? 70 // TODO: Might want to preserve <a> links in the HTML in case user has specified them in their data. EscapeHTML(string original, bool hardSpace)71 public static string EscapeHTML(string original, bool hardSpace) 72 { 73 if (string.IsNullOrEmpty(original)) { 74 return string.Empty; 75 } 76 77 fLogger.WriteInfo(string.Format("EscapeHTML({0})", original)); 78 79 int tabSpaces = GMConfig.Instance.TabSpaces; 80 var sb = new StringBuilder(original.Length); 81 int tabPos = 0; 82 bool doneCRLF = false; 83 bool doneSpace = false; 84 int length = original.Length; 85 int n = 0; 86 foreach (char c in original) { 87 switch (c) { 88 case (char)0x91: 89 case (char)0x92: 90 sb.Append("'"); 91 doneCRLF = false; 92 doneSpace = false; 93 tabPos++; 94 break; 95 case (char)0x93: 96 case (char)0x94: 97 sb.Append("\""); 98 doneCRLF = false; 99 doneSpace = false; 100 tabPos++; 101 break; 102 case '<': 103 sb.Append("<"); 104 doneCRLF = false; 105 doneSpace = false; 106 tabPos++; 107 break; 108 case '>': 109 sb.Append(">"); 110 doneCRLF = false; 111 doneSpace = false; 112 tabPos++; 113 break; 114 case '\"': 115 sb.Append("""); 116 doneCRLF = false; 117 doneSpace = false; 118 tabPos++; 119 break; 120 case '&': 121 sb.Append("&"); 122 doneCRLF = false; 123 doneSpace = false; 124 tabPos++; 125 break; 126 case ' ': 127 if (doneSpace || hardSpace) { 128 sb.Append(" "); 129 } else { 130 sb.Append(' '); 131 doneSpace = true; 132 } 133 doneCRLF = false; 134 tabPos++; 135 break; 136 case '\n': 137 if (!doneCRLF) { 138 sb.Append("<br />"); 139 } 140 doneCRLF = false; // To allow multiple CRLFs to produce multiple <BR />s 141 doneSpace = false; 142 tabPos = 0; 143 break; 144 case '\r': 145 if (!doneCRLF) { 146 sb.Append("<br />"); 147 doneCRLF = true; 148 } 149 doneSpace = false; 150 tabPos = 0; 151 break; 152 case '\t': 153 do { 154 sb.Append(" "); 155 tabPos++; 156 } 157 while ((tabPos % tabSpaces) != 0); 158 doneSpace = true; 159 break; 160 161 default: 162 sb.Append(c); 163 doneCRLF = false; 164 doneSpace = false; 165 tabPos++; 166 break; 167 } 168 ++n; 169 } 170 return sb.ToString(); 171 } 172 173 // Converts all Javascript characters into their escaped versions EscapeJavascript(string original)174 protected static string EscapeJavascript(string original) 175 { 176 if (original == null) { 177 return ""; 178 } 179 180 var sb = new StringBuilder(original.Length); 181 foreach (char c in original) { 182 switch (c) { 183 case '\'': 184 sb.Append("\\'"); 185 break; 186 default: 187 sb.Append(c); 188 break; 189 } 190 } 191 return sb.ToString(); 192 } 193 194 // Converts all invalid sFilename characters into underscores EscapeFilename(string original)195 protected static string EscapeFilename(string original) 196 { 197 fLogger.WriteInfo(string.Format("EscapeFilename({0})", original)); 198 199 if (original == null) { 200 return "_"; 201 } 202 203 const string validChars = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$%'`-@{}~!#()&_^"; 204 205 var sb = new StringBuilder(original.Length); 206 foreach (char c in original) { 207 char cc = c; 208 if (validChars.IndexOf(c) < 0) { 209 cc = '_'; 210 } 211 sb.Append(cc); 212 } 213 return sb.ToString(); 214 } 215 216 // Returns a string with all email addresses replaced by value of sReplacement. ObfuscateEmail(string text)217 protected static string ObfuscateEmail(string text) 218 { 219 if (text == null) { 220 return null; 221 } 222 int nLength = text.Length; 223 var sb = new StringBuilder(nLength); 224 int i = 0; 225 int nNameStart = -1; 226 int nState = 0; 227 const string invalidNameChars = ",\"�$^&*()+=]}[{':;,<>?/\\|`�#~"; 228 const string replacement = "<email address>"; 229 230 while (i < nLength) { 231 char c = text[i]; 232 233 switch (nState) { 234 case 0: 235 // Not seen anything special. 236 if (!char.IsWhiteSpace(c) && c != '@' && c != '.' && invalidNameChars.IndexOf(c) < 0) { 237 // Possible name char, remember where name starts. 238 nState = 1; 239 nNameStart = i; 240 } else { 241 // Can't be an email name. Add it verbatim. 242 sb.Append(c); 243 nState = 0; 244 } 245 break; 246 case 1: 247 // Seen one or more name chars. 248 if (c == '@') { 249 // Now looking for domain. 250 nState = 2; 251 } else if (!char.IsWhiteSpace(c) && invalidNameChars.IndexOf(c) < 0) { 252 // Continue looking through a possible name string. 253 } else { 254 // Can't be an email address. Add what we've got so far and return 255 // to hunting email addresses. 256 sb.Append(text.Substring(nNameStart, i - nNameStart)); 257 sb.Append(c); 258 nState = 0; 259 } 260 break; 261 case 2: 262 // Seen at sign, now looking for domain 263 if (!char.IsWhiteSpace(c) && c != '@' && c != '.' && invalidNameChars.IndexOf(c) < 0) { 264 // Possible domain char. 265 // Now looking for dot among domain chars. 266 nState = 3; 267 } else { 268 // Can't be an email address. Add what we've got so far and return 269 // to hunting email addresses. 270 sb.Append(text.Substring(nNameStart, i - nNameStart)); 271 sb.Append(c); 272 nState = 0; 273 } 274 break; 275 case 3: 276 // Looking for first dot among domain chars 277 if (c == '.') { 278 // Now looking for another domain. 279 nState = 4; 280 } else if (!char.IsWhiteSpace(c) && c != '@' && invalidNameChars.IndexOf(c) < 0) { 281 // A possible domain char, keep looking for dot. 282 } else { 283 // Can't be an email address. Add what we've got so far and return 284 // to hunting email addresses. 285 sb.Append(text.Substring(nNameStart, i - nNameStart)); 286 sb.Append(c); 287 nState = 0; 288 } 289 break; 290 case 4: 291 // Looking for valid domain char to start next domain portion. 292 if (!char.IsWhiteSpace(c) && c != '@' && c != '.' && invalidNameChars.IndexOf(c) < 0) { 293 // A valid domain char. Look for another dot , or end. 294 nState = 5; 295 } else { 296 // Can't be an email address. Add what we've got so far and return 297 // to hunting email addresses. 298 sb.Append(text.Substring(nNameStart, i - nNameStart)); 299 sb.Append(c); 300 nState = 0; 301 } 302 break; 303 case 5: 304 // Looking for a dot or end of domain among valid domain chars 305 if (c == '.') { 306 // Read rest of domain part. 307 nState = 6; 308 } else if (!char.IsWhiteSpace(c) && c != '@' && invalidNameChars.IndexOf(c) < 0) { 309 // Valid domain name. Keep looking for dot or end. 310 } else if (c != '@') { 311 // Found complete email address 312 sb.Append(replacement); 313 sb.Append(c); 314 nState = 0; 315 } else { 316 // Can't be an email address. Add what we've got so far and return 317 // to hunting email addresses. 318 sb.Append(text.Substring(nNameStart, i - nNameStart)); 319 sb.Append(c); 320 nState = 0; 321 } 322 break; 323 case 6: 324 // Looking for valid domain char to start next domain portion, or can end here if address is (name@add.add.) 325 if (!char.IsWhiteSpace(c) && c != '@' && c != '.' && invalidNameChars.IndexOf(c) < 0) { 326 // A valid domain char. Look for another dot , or end. 327 nState = 5; 328 } else { 329 // Found complete email address (ending in a full-stop). 330 sb.Append(replacement); 331 sb.Append('.'); 332 sb.Append(c); 333 nState = 0; 334 } 335 break; 336 } 337 ++i; 338 } 339 340 // Add anything remaining in email addr buffer. 341 if (nState == 5 || nState == 6) { 342 // Found complete email address. 343 sb.Append(replacement); 344 if (nState == 6) { 345 // We ended on a dot. 346 sb.Append('.'); 347 } 348 } else if (nState > 0) { 349 sb.Append(text.Substring(nNameStart, i - nNameStart)); 350 } 351 return sb.ToString(); 352 } 353 354 // Generates navbar at top of page, in header div OutputPageHeader(HTMLFile f, string previousChildLink, string nextChildLink, bool includeIndexLink)355 protected static void OutputPageHeader(HTMLFile f, string previousChildLink, string nextChildLink, bool includeIndexLink) 356 { 357 if (GMConfig.Instance.IncludeNavbar) { 358 string frontPageLink = ""; 359 if (GMConfig.Instance.FrontPageFilename != "") { 360 frontPageLink += string.Concat("<a href=\"", GMConfig.Instance.FrontPageFilename, ".", GMConfig.Instance.HtmlExtension, "\">front page</a>"); 361 } 362 string mainSiteLink = ""; 363 if (GMConfig.Instance.MainWebsiteLink != "") { 364 mainSiteLink += string.Concat("<a href=\"", GMConfig.Instance.MainWebsiteLink, "\">main site</a>"); 365 } 366 367 bool includeNavbar = previousChildLink != "" 368 || nextChildLink != "" 369 || includeIndexLink 370 || frontPageLink != "" 371 || mainSiteLink != ""; 372 373 if (includeNavbar) { 374 f.WriteLine(" <div id=\"header\">"); 375 f.WriteLine(" <ul>"); 376 377 if (previousChildLink != "") { 378 f.WriteLine("<li>{0}</li>", previousChildLink); 379 } 380 381 if (nextChildLink != "") { 382 f.WriteLine("<li>{0}</li>", nextChildLink); 383 } 384 385 if (includeIndexLink) { 386 f.WriteLine(string.Concat("<li><a href=\"individuals1.", GMConfig.Instance.HtmlExtension, "\">index</a></li>")); 387 } 388 389 if (frontPageLink != "") { 390 f.WriteLine("<li>{0}</li>", frontPageLink); 391 } 392 393 if (mainSiteLink != "") { 394 f.WriteLine("<li>{0}</li>", mainSiteLink); 395 } 396 397 f.WriteLine(" </ul>"); 398 f.WriteLine(" </div> <!-- header -->"); 399 f.WriteLine(""); 400 } 401 } 402 } 403 404 // Copies a file from the user's source directory to the website output directory, renaming and resizing as appropriate. 405 // Returns the sFilename of the copy. 406 // sArea is sAsid sub-part of image 407 // sArea is changed to reflect new image size 408 // sArea can be {0,0,0,0} meaning use whole image 409 // stats can be null if we don't care about keeping count of the multimedia files. CopyMultimedia(string fullFilename, string newFilename, int maxWidth, int maxHeight, ref Rectangle rectArea, Stats stats)410 public static string CopyMultimedia(string fullFilename, string newFilename, int maxWidth, int maxHeight, 411 ref Rectangle rectArea, Stats stats) 412 { 413 fLogger.WriteInfo(string.Format("CopyMultimedia( {0}, {1}, {2} )", fullFilename, maxWidth, maxHeight)); 414 415 if (!File.Exists(fullFilename)) { 416 return ""; 417 } 418 419 string result = fullFilename; 420 421 if (newFilename == "") { 422 newFilename = Path.GetFileName(fullFilename); 423 } 424 425 try { 426 string asidFilename; 427 if (rectArea.Width == 0) { 428 asidFilename = fullFilename; 429 } else { 430 asidFilename = string.Concat(fullFilename, ".", rectArea.X.ToString(), ",", rectArea.Y.ToString(), ",", rectArea.Width.ToString(), ",", rectArea.Height.ToString()); 431 } 432 433 if (maxWidth != 0 && maxHeight != 0) { 434 asidFilename = string.Concat(asidFilename, "(", maxWidth.ToString(), "x", maxHeight.ToString(), ")"); 435 } 436 437 if (fullFilename != null && GMConfig.Instance.OutputFolder != null && GMConfig.Instance.OutputFolder != "") { 438 // Have we already copied the sFilename? 439 if (fCopiedFiles.ContainsKey(asidFilename)) { 440 var filenameAndSize = fCopiedFiles[asidFilename]; 441 result = filenameAndSize.FileName; 442 rectArea.Width = filenameAndSize.Width; 443 rectArea.Height = filenameAndSize.Height; 444 } else { 445 // Copy file into output directory 446 if (GMConfig.Instance.CopyMultimedia) { 447 string imageFolder = GMConfig.Instance.ImageFolder; 448 string outputFolder = GMConfig.Instance.OutputFolder; 449 450 if (imageFolder != "") { 451 imageFolder = imageFolder + '\\'; 452 } 453 if (outputFolder != "") { 454 outputFolder = outputFolder + '\\'; 455 } 456 457 string copyFilename = string.Concat(imageFolder, newFilename); 458 string absImageFolder = string.Concat(outputFolder, imageFolder); 459 string absCopyFilename = string.Concat(absImageFolder, newFilename); 460 461 // If image folder doesn't exist, create it 462 if (!File.Exists(absImageFolder) && !Directory.Exists(absImageFolder)) // TODO: this returns false if it exists but you don't have permission! 463 { 464 Directory.CreateDirectory(absImageFolder); // TODO: catch failure to create, e.g. output folder not there yet 465 } 466 467 // If new sFilename already exists, append a number and keep trying 468 uint uCopy = 0; 469 string filePart = Path.GetFileNameWithoutExtension(copyFilename); 470 string extnPart = Path.GetExtension(copyFilename); 471 while (File.Exists(absCopyFilename)) { 472 const string sAdditionalLetters = "abcdefghijklmnopqrstuvwxyz"; 473 if (GMConfig.Instance.RenameMultimedia == false) { 474 uint nCopyPlus = uCopy + 2; 475 copyFilename = string.Concat(imageFolder, filePart, "-", nCopyPlus.ToString(), extnPart); 476 } else if (uCopy >= sAdditionalLetters.Length) { 477 // Once all the extra letters have been used up, put number as "-n", where n starts from 2. 478 uint nCopyMinus = uCopy - (uint)(sAdditionalLetters.Length - 2); 479 copyFilename = string.Concat(imageFolder, filePart, "-", nCopyMinus.ToString(), extnPart); 480 } else { 481 copyFilename = string.Concat(imageFolder, filePart, sAdditionalLetters[(int)uCopy], extnPart); 482 } 483 uCopy++; 484 485 absCopyFilename = string.Concat(outputFolder, copyFilename); 486 } 487 488 fLogger.WriteInfo(string.Format("Copying \"{0}\" to \"{1}\"", fullFilename, absCopyFilename)); 489 490 File.Copy(fullFilename, absCopyFilename, true); 491 492 File.SetAttributes(fullFilename, FileAttributes.Normal); // Make any Read-Only files read-write. 493 if (maxWidth != 0 && maxHeight != 0) { 494 // It must be a picture file 495 copyFilename = ConvertAndCropImage(outputFolder, copyFilename, ref rectArea, maxWidth, maxHeight); 496 } 497 fCopiedFiles[asidFilename] = new FilenameAndSize(copyFilename, rectArea.Width, rectArea.Height); 498 result = copyFilename; 499 } else { 500 if (GMConfig.Instance.RelativiseMultimedia) { 501 // TODO: make path of sFilename relative to MainForm.s_config.m_outputFolder 502 string sRelativeFilename = fullFilename; 503 result = sRelativeFilename; 504 } 505 } 506 if (stats != null) { 507 stats.MultimediaFiles++; 508 } 509 } 510 } 511 result = result.Replace('\\', '/'); 512 } catch (IOException e) { 513 fLogger.WriteError("Caught IO Exception : ", e); 514 result = ""; 515 } catch (ArgumentException e) { 516 fLogger.WriteError("Caught Argument Exception : ", e); 517 result = ""; 518 } catch (HTMLException e) { 519 fLogger.WriteError("Caught HTML Exception : ", e); 520 result = ""; 521 } catch (Exception e) { 522 fLogger.WriteError("Caught generic exception : ", e); 523 result = ""; 524 } 525 526 return result; 527 } 528 529 // Outputs the HTML to display the W3C Valid XHTML image on the page. OutputValiditySticker(HTMLFile f)530 protected void OutputValiditySticker(HTMLFile f) 531 { 532 f.WriteLine("<p class=\"plain\">"); 533 f.WriteLine("<a href=\"http://validator.w3.org/check?uri=referer\"><img"); 534 f.WriteLine("src=\"" + fW3CFile + "\""); 535 f.WriteLine("style=\"margin-top:4px\""); 536 f.WriteLine("alt=\"Valid XHTML 1.0 Strict\" height=\"31\" width=\"88\" /></a>"); 537 f.WriteLine("</p>"); 538 } 539 540 // Creates link HTML for the individual e.g. <a href="indiI1.html">Fred Bloggs</a> MakeLink(GDMIndividualRecord ir)541 protected static string MakeLink(GDMIndividualRecord ir) 542 { 543 string name = ir.GetPrimaryFullName(); 544 string dummy = ""; 545 if (name == "") { 546 name = GMConfig.Instance.UnknownName; 547 } else if (!GMHelper.GetVisibility(ir) && !GMConfig.Instance.UseWithheldNames) { 548 name = GMConfig.Instance.ConcealedName; 549 } else { 550 name = GMHelper.CapitaliseName(name, ref dummy, ref dummy); 551 } 552 return MakeLink(ir, name); 553 } 554 MakeNote(string noteStr)555 protected static string MakeNote(string noteStr) 556 { 557 if (!string.IsNullOrEmpty(noteStr)) { 558 return string.Concat("<p class=\"eventNote\">", EscapeHTML(noteStr, false), "</p>"); 559 } 560 return string.Empty; 561 } 562 563 // Creates link HTML for the individual e.g. <a href="indiI1.html">Next Child</a>. Uses name provided by caller. MakeLink(GDMIndividualRecord ir, string name)564 protected static string MakeLink(GDMIndividualRecord ir, string name) 565 { 566 string link; 567 if (!GMHelper.GetVisibility(ir)) { 568 // TODO: Why are we linking to invisible people? 569 link = EscapeHTML(name, true); 570 } else { 571 link = string.Concat("<a href=\"", GetIndividualHTMLFilename(ir), "\">", EscapeHTML(name, false), "</a>"); 572 } 573 return link; 574 } 575 576 // Returns a string to use as a sFilename for this individual's HTML page. 577 // The string is just the sFilename, not a fully qualified path. GetIndividualHTMLFilename(GDMIndividualRecord ir)578 protected static string GetIndividualHTMLFilename(GDMIndividualRecord ir) 579 { 580 string relativeFilename = string.Concat("indi", ir.XRef, ".", GMConfig.Instance.HtmlExtension); 581 if (GMConfig.Instance.UserRecFilename && ir.HasUserReferences) { 582 GDMUserReference urn = ir.UserReferences[0]; 583 string filenameUserRef = EscapeFilename(urn.StringValue); 584 if (filenameUserRef.Length > 0) { 585 relativeFilename = string.Concat("indi", filenameUserRef, ".", GMConfig.Instance.HtmlExtension); 586 } 587 } 588 return relativeFilename; 589 } 590 591 // Crops the specified image file to the given size. Also converts non-standard formats to standard ones. 592 // Returns sFilename in case extension has changed. 593 // sArea is changed to reflect new image size ConvertAndCropImage(string folder, string fileName, ref Rectangle rectArea, int maxWidth, int maxHeight)594 private static string ConvertAndCropImage(string folder, string fileName, ref Rectangle rectArea, int maxWidth, int maxHeight) 595 { 596 fLogger.WriteInfo(string.Format("ConvertAndCropImage( {0}, {1} )", folder != null ? folder : "null", fileName != null ? fileName : "null")); 597 598 string absFilename = string.Concat(folder, fileName); 599 600 Image image = null; 601 try { 602 image = Image.FromFile(absFilename); 603 } catch (OutOfMemoryException) { 604 // Image is not a GDI compatible format 605 image = null; 606 } 607 608 if (image == null) { 609 throw (new HTMLException("Unknown image format for file " + absFilename)); // Let caller sort it out. 610 } 611 612 Rectangle rectNewArea; 613 if (rectArea.Width <= 0 || rectArea.Height <= 0) { 614 SizeF s = image.PhysicalDimension; 615 if (s.Width <= maxWidth && s.Height <= maxHeight) { 616 maxWidth = (int)s.Width; 617 maxHeight = (int)s.Height; 618 // Nothing needs to be done, bitmap already correct size. 619 // Carry on with conversion. 620 } 621 rectNewArea = new Rectangle(0, 0, (int)s.Width, (int)s.Height); 622 rectArea.X = 0; 623 rectArea.Y = 0; 624 rectArea.Width = rectNewArea.Width; 625 rectArea.Height = rectNewArea.Height; 626 } else { 627 rectNewArea = new Rectangle(0, 0, rectArea.Width, rectArea.Height); 628 } 629 630 if (maxWidth != 0 && maxHeight != 0) { 631 // If image is too big then shrink it. (Can't always use GetThumbnailImage because that might use embedded thumbnail). 632 GMHelper.ScaleAreaToFit(ref rectNewArea, maxWidth, maxHeight); 633 } 634 635 Bitmap bitmapNew = new Bitmap(rectNewArea.Width, rectNewArea.Height, PixelFormat.Format24bppRgb); 636 Graphics graphicsNew = Graphics.FromImage(bitmapNew); 637 638 graphicsNew.DrawImage(image, rectNewArea, rectArea, GraphicsUnit.Pixel); 639 image.Dispose(); 640 641 // Find which format to save in. TODO: There must be a more elegant way!! 642 string extn = Path.GetExtension(fileName); 643 string filepart = Path.GetDirectoryName(fileName); 644 filepart += "\\" + Path.GetFileNameWithoutExtension(fileName); 645 ImageFormat imageFormat; 646 switch (extn.ToLower()) { 647 case ".jpg": 648 case ".jpeg": 649 extn = ".jpg"; 650 imageFormat = ImageFormat.Jpeg; 651 break; 652 case ".gif": 653 imageFormat = ImageFormat.Gif; 654 break; 655 case ".bmp": 656 imageFormat = ImageFormat.Bmp; 657 break; 658 case ".tif": 659 case ".tiff": 660 // Tif's don't display in browsers, so convert to png. 661 imageFormat = ImageFormat.Png; 662 extn = ".png"; 663 break; 664 case ".exif": 665 imageFormat = ImageFormat.Exif; 666 break; 667 case ".png": 668 imageFormat = ImageFormat.Png; 669 break; 670 default: 671 imageFormat = ImageFormat.Jpeg; 672 break; 673 } 674 675 string filenameNew = filepart + extn; 676 string absFilenameNew = string.Concat(folder, filenameNew); 677 try { 678 if (File.Exists(absFilename)) { 679 // Delete the old file (e.g. if converting from tif to png) 680 File.Delete(absFilename); 681 } 682 } catch (Exception e) { 683 fLogger.WriteError(string.Format("Caught exception while removing old bitmap file {0}", absFilename), e); 684 } 685 try { 686 if (File.Exists(absFilenameNew)) { 687 // Delete any existing file 688 File.SetAttributes(absFilenameNew, FileAttributes.Normal); 689 File.Delete(absFilenameNew); 690 } 691 bitmapNew.Save(absFilenameNew, imageFormat); 692 } catch (Exception e) { 693 fLogger.WriteError(string.Format("Caught exception while writing bitmap file {0}", filenameNew), e); 694 filenameNew = ""; 695 } 696 graphicsNew.Dispose(); 697 bitmapNew.Dispose(); 698 699 rectArea = rectNewArea; 700 return filenameNew; 701 } 702 } 703 } 704