1 // Copyright (C) 2009-2013 pdfcrowd.com 2 // 3 // Permission is hereby granted, free of charge, to any person 4 // obtaining a copy of this software and associated documentation 5 // files (the "Software"), to deal in the Software without 6 // restriction, including without limitation the rights to use, 7 // copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following 10 // conditions: 11 // 12 // The above copyright notice and this permission notice shall be 13 // included in all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 // OTHER DEALINGS IN THE SOFTWARE. 23 24 using System; 25 using System.Text; 26 using System.Net; 27 using System.IO; 28 using System.Web; 29 using System.Diagnostics; 30 using System.Collections; 31 using System.Collections.Generic; 32 using System.Collections.Specialized; 33 using System.Net.Security; 34 35 namespace pdfcrowd 36 { 37 // 38 // Pdfcrowd API client. 39 // 40 public class Client 41 { 42 // 43 // Client constructor. 44 // 45 // username - your username at Pdfcrowd 46 // api_key - your API key 47 // 48 public Client(string username, string api_key) 49 { 50 useSSL(false); 51 fields.Add("username", username); 52 fields.Add("key", api_key); 53 fields.Add("pdf_scaling_factor", "1"); 54 fields.Add("html_zoom", "200"); 55 } 56 57 // 58 // Client constructor. 59 // 60 // username - your username at Pdfcrowd 61 // api_key - your API key 62 // 63 // 64 public Client(string username, string api_key, string hostname) 65 { 66 fields.Add("username", username); 67 fields.Add("key", api_key); 68 fields.Add("pdf_scaling_factor", "1"); 69 fields.Add("html_zoom", "200"); 70 HOST = hostname; 71 useSSL(false); 72 } 73 74 75 // 76 // Converts a web page. 77 // 78 // uri - a web page URL 79 // out_stream - a System.IO.Stream implementation 80 // 81 public void convertURI(string uri, Stream out_stream) 82 { 83 convert(out_stream, "uri", uri); 84 } 85 86 // 87 // Converts an in-memory html document. 88 // 89 // content - a string containing a html document 90 // out_stream - a System.IO.Stream implementation 91 // 92 public void convertHtml(string content, Stream out_stream) 93 { 94 convert(out_stream, "html", content); 95 } 96 97 // 98 // Converts an html file. 99 // 100 // fpath - a path to an html file 101 // out_stream - a System.IO.Stream implementation 102 // 103 public void convertFile(string fpath, Stream out_stream) 104 { 105 post_multipart(fpath, out_stream); 106 } 107 108 // 109 // Returns the number of available conversion tokens. 110 // 111 public int numTokens() 112 { 113 string uri = String.Format("{0}user/{1}/tokens/", api_uri, fields["username"]); 114 MemoryStream stream = new MemoryStream(); 115 call_api(uri, stream, null); 116 stream.Position = 0; 117 string value = read_stream(stream); 118 return Int32.Parse(value); 119 } 120 121 122 public void useSSL(bool use_ssl) 123 { 124 if(use_ssl) 125 { 126 api_uri = string.Format("https://{0}:{1}{2}", HOST, HTTPS_PORT, API_SELECTOR_BASE); 127 } 128 else 129 { 130 api_uri = string.Format("http://{0}:{1}{2}", HOST, HTTP_PORT, API_SELECTOR_BASE); 131 } 132 } 133 134 public void setUsername(string username) 135 { 136 fields["username"] = username; 137 } 138 139 public void setApiKey(string key) 140 { 141 fields["key"] = key; 142 } 143 144 public void setPageWidth(string value) 145 { 146 fields["width"] = value; 147 } 148 149 public void setPageWidth(double value) 150 { 151 fields["width"] = value.ToString();; 152 } 153 154 public void setPageHeight(string value) 155 { 156 fields["height"] = value; 157 } 158 159 public void setPageHeight(double value) 160 { 161 fields["height"] = value.ToString(); 162 } 163 164 public void setHorizontalMargin(double value) 165 { 166 fields["margin_right"] = value.ToString(); 167 fields["margin_left"] = value.ToString(); 168 } 169 170 public void setHorizontalMargin(string value) 171 { 172 fields["margin_right"] = value; 173 fields["margin_left"] = value; 174 } 175 176 public void setVerticalMargin(double value) 177 { 178 fields["margin_top"] = value.ToString(); 179 fields["margin_bottom"] = value.ToString(); 180 } 181 182 public void setVerticalMargin(string value) 183 { 184 fields["margin_top"] = value; 185 fields["margin_bottom"] = value; 186 } 187 188 public void setPageMargins(string top, string right, string bottom, string left) 189 { 190 fields["margin_top"] = top; 191 fields["margin_right"] = right; 192 fields["margin_bottom"] = bottom; 193 fields["margin_left"] = left; 194 } 195 196 public void setEncrypted(bool value) 197 { 198 fields["encrypted"] = value ? "true" : null; 199 } 200 201 public void setEncrypted() 202 { 203 setEncrypted(true); 204 } 205 206 public void setUserPassword(string pwd) 207 { 208 fields["user_pwd"] = pwd; 209 } 210 211 public void setOwnerPassword(string pwd) 212 { 213 fields["owner_pwd"] = pwd; 214 } 215 216 public void setNoPrint(bool value) 217 { 218 fields["no_print"] = value ? "true" : null; 219 } 220 221 public void setNoPrint() 222 { 223 setNoPrint(true); 224 } 225 226 public void setNoModify(bool value) 227 { 228 fields["no_modify"] = value ? "true" : null; 229 } 230 231 public void setNoModify() 232 { 233 setNoModify(true); 234 } 235 236 public void setNoCopy(bool value) 237 { 238 fields["no_copy"] = value ? "true" : null; 239 } 240 241 public void setNoCopy() 242 { 243 setNoCopy(true); 244 } 245 246 // constants for setPageLayout() 247 static public int SINGLE_PAGE = 1; 248 static public int CONTINUOUS = 2; 249 static public int CONTINUOUS_FACING = 3; 250 251 public void setPageLayout(int value) 252 { 253 Debug.Assert(value > 0 && value <= 3); 254 fields["page_layout"] = value.ToString(); 255 } 256 257 // constants for setPageMode() 258 static public int NONE_VISIBLE = 1; 259 static public int THUMBNAILS_VISIBLE = 2; 260 static public int FULLSCREEN = 3; 261 262 public void setPageMode(int value) 263 { 264 Debug.Assert(value > 0 && value <= 3); 265 fields["page_mode"] = value.ToString(); 266 } 267 268 public void setFooterText(string value) { 269 fields["footer_text"] = value; 270 } 271 272 public void enableImages() { 273 enableImages(true); 274 } 275 276 public void enableImages(bool value) { 277 fields["no_images"] = value ? null : "true"; 278 } 279 280 public void enableBackgrounds() { 281 enableBackgrounds(true); 282 } 283 284 public void enableBackgrounds(bool value) { 285 fields["no_backgrounds"] = value ? null : "true"; 286 } 287 288 public void setHtmlZoom(float value) { 289 fields["html_zoom"] = value.ToString(); 290 } 291 292 public void enableJavaScript() { 293 enableJavaScript(true); 294 } 295 296 public void enableJavaScript(bool value) { 297 fields["no_javascript"] = value ? null : "true"; 298 } 299 300 public void enableHyperlinks() { 301 enableHyperlinks(true); 302 } 303 304 public void enableHyperlinks(bool value) { 305 fields["no_hyperlinks"] = value ? null : "true"; 306 } 307 308 public void setDefaultTextEncoding(string value) { 309 fields["text_encoding"] = value; 310 } 311 312 public void usePrintMedia() { 313 usePrintMedia(true); 314 } 315 316 public void usePrintMedia(bool value) { 317 fields["use_print_media"] = value ? "true" : null; 318 } 319 320 public void setMaxPages(int value) { 321 fields["max_pages"] = value.ToString(); 322 } 323 324 public void enablePdfcrowdLogo() { 325 enablePdfcrowdLogo(true); 326 } 327 328 public void enablePdfcrowdLogo(bool value) { 329 fields["pdfcrowd_logo"] = value ? "true" : null; 330 } 331 332 // constants for setInitialPdfZoomType() 333 static public int FIT_WIDTH = 1; 334 static public int FIT_HEIGHT = 2; 335 static public int FIT_PAGE = 3; 336 337 public void setInitialPdfZoomType(int value) { 338 Debug.Assert(value>0 && value<=3); 339 fields["initial_pdf_zoom_type"] = value.ToString(); 340 } 341 342 public void setInitialPdfExactZoom(float value) { 343 fields["initial_pdf_zoom_type"] = "4"; 344 fields["initial_pdf_zoom"] = value.ToString(); 345 } 346 347 public void setAuthor(string value) { 348 fields["author"] = value; 349 } 350 351 public void setFailOnNon200(bool value) { 352 fields["fail_on_non200"] = value ? "true" : null; 353 } 354 355 public void setPdfScalingFactor(float value) { 356 fields["pdf_scaling_factor"] = value.ToString(); 357 } 358 359 public void setFooterHtml(string value) { 360 fields["footer_html"] = value; 361 } 362 363 public void setFooterUrl(string value) { 364 fields["footer_url"] = value; 365 } 366 367 public void setHeaderHtml(string value) { 368 fields["header_html"] = value; 369 } 370 371 public void setHeaderUrl(string value) { 372 fields["header_url"] = value; 373 } 374 375 public void setPageBackgroundColor(string value) { 376 fields["page_background_color"] = value; 377 } 378 379 380 381 382 public void setTransparentBackground() { 383 setTransparentBackground(true); 384 } 385 386 public void setTransparentBackground(bool val) { 387 fields["transparent_background"] = val ? "true" : null; 388 } 389 390 391 public void setPageNumberingOffset(int value) { 392 fields["page_numbering_offset"] = value.ToString(); 393 } 394 395 public void setHeaderFooterPageExcludeList(string value) { 396 fields["header_footer_page_exclude_list"] = value; 397 } 398 399 public void setWatermark(string url, float offset_x, float offset_y) { 400 fields["watermark_url"] = url; 401 fields["watermark_offset_x"] = offset_x.ToString(); 402 fields["watermark_offset_y"] = offset_y.ToString(); 403 } 404 405 public void setWatermark(string url, string offset_x, string offset_y) { 406 fields["watermark_url"] = url; 407 fields["watermark_offset_x"] = offset_x; 408 fields["watermark_offset_y"] = offset_y; 409 } 410 411 public void setWatermarkRotation(double angle) { 412 fields["watermark_rotation"] = angle.ToString(); 413 } 414 415 public void setWatermarkInBackground() { 416 setWatermarkInBackground(true); 417 } 418 419 public void setWatermarkInBackground(bool val) { 420 fields["watermark_in_background"] = val ? "true" : null; 421 } 422 423 424 425 426 // --------------------------------------------------------------------------- 427 // 428 // Private stuff 429 // 430 431 static string API_SELECTOR_BASE = "/api/"; 432 433 public string HOST = "pdfcrowd.com"; 434 static public int HTTP_PORT = 80; 435 static public int HTTPS_PORT = 443; 436 437 StringDictionary fields = new StringDictionary(); 438 string api_uri; 439 440 441 private void convert(Stream out_stream, string method, string src) 442 { 443 string uri = String.Format("{0}pdf/convert/{1}/", api_uri, method); 444 call_api(uri, out_stream, src); 445 } 446 447 private static void CopyStream(Stream input, Stream output) 448 { 449 byte[] buffer = new byte[32768]; 450 while(true) 451 { 452 int read = input.Read(buffer, 0, buffer.Length); 453 if(read <= 0) 454 return; 455 output.Write(buffer, 0, read); 456 } 457 } 458 459 460 private void call_api(string uri, Stream out_stream, string src) 461 { 462 StringDictionary extra_data = new StringDictionary(); 463 if (src != null) 464 { 465 extra_data["src"] = src; 466 } 467 string data = encode_post_data(extra_data); 468 do_request(uri, out_stream, data, "application/x-www-form-urlencoded"); 469 } 470 471 private static void do_request(string uri, Stream out_stream, object data, string content_type) 472 { 473 WebRequest request = WebRequest.Create(uri); 474 request.Method = "POST"; 475 476 byte[] byteArray; 477 if ((data is byte[])) 478 { 479 byteArray = (byte[])data; 480 } 481 else 482 { 483 byteArray = Encoding.UTF8.GetBytes((string)data); 484 } 485 request.ContentType = content_type; 486 request.ContentLength = byteArray.Length; 487 try 488 { 489 using(Stream dataStream = request.GetRequestStream()) 490 { 491 dataStream.Write(byteArray, 0, byteArray.Length); 492 } 493 494 // Get the response. 495 using(HttpWebResponse response = (HttpWebResponse) request.GetResponse()) 496 { 497 if(response.StatusCode == HttpStatusCode.OK) 498 { 499 // Get the stream containing content returned by the server. 500 using(Stream dataStream = response.GetResponseStream()) 501 { 502 CopyStream(dataStream, out_stream); 503 out_stream.Position = 0; 504 } 505 } 506 else 507 { 508 throw new Error(response.StatusDescription, response.StatusCode); 509 } 510 } 511 } 512 catch(WebException why) 513 { 514 if (why.Status == WebExceptionStatus.ProtocolError) 515 { 516 HttpWebResponse response = (HttpWebResponse)why.Response; 517 518 MemoryStream stream = new MemoryStream(); 519 CopyStream(response.GetResponseStream(), stream); 520 stream.Position = 0; 521 string err = read_stream(stream); 522 throw new Error(err, response.StatusCode); 523 } else { 524 string innerException = ""; 525 if (why.InnerException != null) 526 { 527 innerException = "\n" + why.InnerException.Message; 528 } 529 throw new Error(why.Message + innerException, HttpStatusCode.Unused); 530 } 531 } 532 } 533 534 private string encode_post_data(StringDictionary extra_data) 535 { 536 StringDictionary data = new StringDictionary(); 537 if(extra_data != null) 538 { 539 foreach(DictionaryEntry entry in extra_data) 540 { 541 if(entry.Value != null) 542 { 543 data.Add(entry.Key.ToString(), entry.Value.ToString()); 544 } 545 } 546 } 547 548 foreach(DictionaryEntry entry in fields) 549 { 550 if(entry.Value != null) 551 { 552 data.Add(entry.Key.ToString(), entry.Value.ToString()); 553 } 554 } 555 string result = ""; 556 int i = 0; 557 foreach(DictionaryEntry entry in data) 558 { 559 result += HttpUtility.UrlEncode(entry.Key.ToString()) + "=" + HttpUtility.UrlEncode(entry.Value.ToString()); 560 if(i < data.Count) 561 { 562 result += "&"; 563 } 564 } 565 return result.Substring(0, result.Length - 1); 566 } 567 568 private static string boundary = "----------ThIs_Is_tHe_bOUnDary_$"; 569 private static string multipart_content_type = "multipart/form-data; boundary=" + boundary; 570 private static string new_line = "\r\n"; 571 572 private static string get_mime_type(string fileName) 573 { 574 string mimeType = "application/octet-stream"; 575 string ext = System.IO.Path.GetExtension(fileName).ToLower(); 576 Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext); 577 if(regKey != null && regKey.GetValue("Content Type") != null) 578 mimeType = regKey.GetValue("Content Type").ToString(); 579 return mimeType; 580 } 581 582 private byte[] encode_multipart_post_data(string filename) 583 { 584 MemoryStream memw = new MemoryStream(); 585 BinaryWriter retval = new BinaryWriter(memw); 586 UTF8Encoding utf8 = new UTF8Encoding(); 587 588 string result = ""; 589 foreach(DictionaryEntry entry in fields) 590 { 591 if(entry.Value != null) 592 { 593 result += "--" + boundary + new_line; 594 result += String.Format("Content-Disposition: form-data; name=\"{0}\"", entry.Key) + new_line; 595 result += new_line; 596 result += entry.Value.ToString() + new_line; 597 } 598 } 599 // filename 600 result += "--" + boundary + new_line; 601 result += String.Format("Content-Disposition: form-data; name=\"src\"; filename=\"{0}\"", filename) + new_line; 602 result += "Content-Type: " + get_mime_type(filename) + new_line; 603 result += new_line; 604 retval.Write(utf8.GetBytes(result)); 605 // filename contents 606 using(FileStream fin = File.OpenRead(filename)) 607 { 608 byte[] b = new byte[8192]; 609 int r; 610 while ((r = fin.Read(b, 0, b.Length)) > 0) 611 retval.Write(b, 0, r); 612 } 613 // finalize 614 result = new_line + "--" + boundary + "--" + new_line; 615 result += new_line; 616 617 retval.Write(utf8.GetBytes(result)); 618 retval.Flush(); 619 return memw.ToArray(); 620 } 621 622 private static string read_stream(Stream stream) 623 { 624 using(StreamReader reader = new StreamReader(stream, Encoding.UTF8)) 625 { 626 return reader.ReadToEnd(); 627 } 628 } 629 630 private void post_multipart(string fpath, Stream out_stream) 631 { 632 byte[] data = encode_multipart_post_data(fpath); 633 do_request(api_uri + "pdf/convert/html/", out_stream, data, multipart_content_type); 634 } 635 636 637 } 638 }