1 // Copyright (C) 2010-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 package com.pdfcrowd; 25 26 import java.util.*; 27 import java.io.*; 28 import java.net.*; 29 import javax.net.ssl.*; 30 31 // 32 // Pdfcrowd API client. 33 // 34 public class Client { 35 36 private HashMap<String,String> fields; 37 private boolean m_useSSL = false; 38 39 // 40 // Client constructor. 41 // 42 // username - your username at Pdfcrowd 43 // apikey - your API key 44 // 45 public Client(String username, String apikey) { 46 init(username, apikey, API_HOSTNAME); 47 } 48 49 // 50 // Converts a web page. 51 // 52 // uri - a web page URL 53 // outStream - an output stream (java.io.OutputStream) 54 // 55 public void convertURI(String uri, OutputStream outStream) { 56 byte[] data = encodePostData(uri); 57 callAPI(data, "pdf/convert/uri/", outStream, URLENCODED); 58 } 59 60 // 61 // Converts an in-memory html document. 62 // 63 // html - a string containing a html document 64 // outStream - an output stream (java.io.OutputStream) 65 // 66 public void convertHtml(String html, OutputStream outStream) { 67 byte[] data = encodePostData(html); 68 callAPI(data, "pdf/convert/html/", outStream, URLENCODED); 69 } 70 71 // 72 // Converts an html file. 73 // 74 // path - a path to an html file 75 // outStream - an output stream (java.io.OutputStream) 76 // 77 public void convertFile(String path, OutputStream outStream) { 78 ByteArrayOutputStream data = encodeMultipartPostData(path); 79 callAPI(data, "pdf/convert/html/", outStream, MULTIPART); 80 } 81 82 // 83 // Returns the number of available conversion tokens. 84 // 85 public int numTokens() { 86 byte[] data = encodePostData(null); 87 ByteArrayOutputStream tokens = new ByteArrayOutputStream(); 88 callAPI(data, "user/" + fields.get("username") + "/tokens/", tokens, URLENCODED); 89 return Integer.parseInt(tokens.toString()); 90 } 91 92 public void useSSL(boolean val) { 93 m_useSSL = val; 94 } 95 96 public void setUsername(String username) { 97 fields.put("username", username); 98 } 99 100 public void setApiKey(String key) { 101 fields.put("key", key); 102 } 103 104 public void setPageWidth(double value) { 105 fields.put("width", doubleToString(value)); 106 } 107 108 public void setPageWidth(String value) { 109 fields.put("width", value); 110 } 111 112 113 public void setPageHeight(double value) { 114 fields.put("height", doubleToString(value)); 115 } 116 117 public void setPageHeight(String value) { 118 fields.put("height", value); 119 } 120 121 public void setHorizontalMargin(double value) { 122 fields.put("margin_right", doubleToString(value)); 123 fields.put("margin_left", doubleToString(value)); 124 } 125 126 public void setHorizontalMargin(String value) { 127 fields.put("margin_right", value); 128 fields.put("margin_left", value); 129 } 130 131 public void setVerticalMargin(double value) { 132 fields.put("margin_top", doubleToString(value)); 133 fields.put("margin_bottom", doubleToString(value)); 134 } 135 136 public void setVerticalMargin(String value) { 137 fields.put("margin_top", value); 138 fields.put("margin_bottom", value); 139 } 140 141 public void setPageMargins(String top, String right, String bottom, String left) { 142 fields.put("margin_top", top); 143 fields.put("margin_right", right); 144 fields.put("margin_bottom", bottom); 145 fields.put("margin_left", left); 146 } 147 148 149 public void setEncrypted() { 150 setEncrypted(true); 151 } 152 153 public void setEncrypted(boolean value) { 154 fields.put("encrypted", value ? "true" : null); 155 } 156 157 public void setUserPassword(String pwd) { 158 fields.put("user_pwd", pwd); 159 } 160 161 public void setOwnerPassword(String pwd) { 162 fields.put("owner_pwd", pwd); 163 } 164 165 public void setNoPrint() { 166 setNoPrint(true); 167 } 168 169 public void setNoPrint(boolean val) { 170 fields.put("no_print", val ? "true" : null); 171 } 172 173 public void setNoModify() { 174 setNoModify(true); 175 } 176 177 public void setNoModify(boolean val) { 178 fields.put("no_modify", val ? "true" : null); 179 } 180 181 public void setNoCopy() { 182 setNoCopy(true); 183 } 184 185 public void setNoCopy(boolean val) { 186 fields.put("no_copy", val ? "true" : null); 187 } 188 189 // constants for setPageLayout() 190 public static int SINGLE_PAGE = 1; 191 public static int CONTINUOUS = 2; 192 public static int CONTINUOUS_FACING = 3; 193 194 public void setPageLayout(int value) { 195 assert value > 0 && value <= 3; 196 fields.put("page_layout", Integer.toString(value)); 197 } 198 199 // constants for setPageMode() 200 public static int NONE_VISIBLE = 1; 201 public static int THUMBNAILS_VISIBLE = 2; 202 public static int FULLSCREEN = 3; 203 204 public void setPageMode(int value) { 205 assert value > 0 && value <= 3; 206 fields.put("page_mode", Integer.toString(value)); 207 } 208 209 public void setFooterText(String value) { 210 fields.put("footer_text", value); 211 } 212 213 public void enableImages() { 214 enableImages(true); 215 } 216 217 public void enableImages(boolean value) { 218 fields.put("no_images", value ? null : "true"); 219 } 220 221 public void enableBackgrounds() { 222 enableBackgrounds(true); 223 } 224 225 public void enableBackgrounds(boolean value) { 226 fields.put("no_backgrounds", value ? null : "true"); 227 } 228 229 public void setHtmlZoom(double value) { 230 fields.put("html_zoom", Double.toString(value)); 231 } 232 233 public void enableJavaScript() { 234 enableJavaScript(true); 235 } 236 237 public void enableJavaScript(boolean value) { 238 fields.put("no_javascript", value ? null : "true"); 239 } 240 241 public void enableHyperlinks() { 242 enableHyperlinks(true); 243 } 244 245 public void enableHyperlinks(boolean value) { 246 fields.put("no_hyperlinks", value ? null : "true"); 247 } 248 249 public void setDefaultTextEncoding(String value) { 250 fields.put("text_encoding", value); 251 } 252 253 public void usePrintMedia() { 254 usePrintMedia(true); 255 } 256 257 public void usePrintMedia(boolean value) { 258 fields.put("use_print_media", value ? "true" : null); 259 } 260 261 public void setMaxPages(int value) { 262 fields.put("max_pages", Integer.toString(value)); 263 } 264 265 public void enablePdfcrowdLogo() { 266 enablePdfcrowdLogo(true); 267 } 268 269 public void enablePdfcrowdLogo(boolean value) { 270 fields.put("pdfcrowd_logo", value ? "true" : null); 271 } 272 273 // constants for setInitialPdfZoomType() 274 public static int FIT_WIDTH = 1; 275 public static int FIT_HEIGHT = 2; 276 public static int FIT_PAGE = 3; 277 278 public void setInitialPdfZoomType(int value) { 279 assert value>0 && value<=3; 280 fields.put("initial_pdf_zoom_type", Integer.toString(value)); 281 } 282 283 public void setInitialPdfExactZoom(double value) { 284 fields.put("initial_pdf_zoom_type", "4"); 285 fields.put("initial_pdf_zoom", Double.toString(value)); 286 } 287 288 public Client(String username, String apikey, String api_hostname) { 289 init(username, apikey, api_hostname); 290 } 291 292 public void setAuthor(String value) { 293 fields.put("author", value); 294 } 295 296 public void setFailOnNon200(boolean value) { 297 fields.put("fail_on_non200", value ? "true" : null); 298 } 299 300 public void setPdfScalingFactor(double value) { 301 fields.put("pdf_scaling_factor", doubleToString(value)); 302 } 303 304 public void setFooterHtml(String value) { 305 fields.put("footer_html", value); 306 } 307 308 public void setFooterUrl(String value) { 309 fields.put("footer_url", value); 310 } 311 312 public void setHeaderHtml(String value) { 313 fields.put("header_html", value); 314 } 315 316 public void setHeaderUrl(String value) { 317 fields.put("header_url", value); 318 } 319 320 public void setPageBackgroundColor(String value) { 321 fields.put("page_background_color", value); 322 } 323 324 public void setTransparentBackground() { 325 setTransparentBackground(true); 326 } 327 328 public void setTransparentBackground(boolean val) { 329 fields.put("transparent_background", val ? "true" : null); 330 } 331 332 public void setPageNumberingOffset(int value) { 333 fields.put("page_numbering_offset", Integer.toString(value)); 334 } 335 336 public void setHeaderFooterPageExcludeList(String value) { 337 fields.put("header_footer_page_exclude_list", value); 338 } 339 340 public void setWatermark(String url, double offset_x, double offset_y) { 341 fields.put("watermark_url", url); 342 fields.put("watermark_offset_x", Double.toString(offset_x)); 343 fields.put("watermark_offset_y", Double.toString(offset_y)); 344 } 345 346 public void setWatermark(String url, String offset_x, String offset_y) { 347 fields.put("watermark_url", url); 348 fields.put("watermark_offset_x", offset_x); 349 fields.put("watermark_offset_y", offset_y); 350 } 351 352 public void setWatermarkRotation(double angle) { 353 fields.put("watermark_rotation", Double.toString(angle)); 354 } 355 356 public void setWatermarkInBackground() { 357 setWatermarkInBackground(true); 358 } 359 360 public void setWatermarkInBackground(boolean val) { 361 fields.put("watermark_in_background", val ? "true" : null); 362 } 363 364 365 366 367 // ---------------------------------------------------------------------- 368 // Private stuff 369 // 370 371 private static String URLENCODED = new String("application/x-www-form-urlencoded"); 372 private static String MULTIPART_BOUNDARY = new String("----------ThIs_Is_tHe_bOUnDary_$"); 373 private static String MULTIPART = new String("multipart/form-data; boundary=" + MULTIPART_BOUNDARY); 374 375 public static String API_HOSTNAME = new String("pdfcrowd.com"); 376 public static int API_HTTP_PORT = 80; 377 public static int API_HTTPS_PORT = 443; 378 private String api_hostname; 379 380 381 private final static HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() { 382 public boolean verify(String hostname, SSLSession session) { 383 return true; 384 //return "pdfcrowd.com".equals(hostname); 385 } 386 }; 387 388 private void init(String username, String apikey, String apihost) { 389 fields = new HashMap<String,String>(); 390 fields.put("username", username); 391 fields.put("key", apikey); 392 fields.put("pdf_scaling_factor", "1.0"); 393 fields.put("html_zoom", "200"); 394 api_hostname = apihost; 395 } 396 397 398 private String doubleToString(double val) { 399 return String.format(Locale.US, "%.5f", val); 400 } 401 402 private static void copyStream(InputStream in, OutputStream out) throws IOException { 403 byte[] buffer = new byte[8192]; 404 while (true) { 405 int bytesRead = in.read(buffer, 0, 8192); 406 if (bytesRead == -1) break; 407 out.write(buffer, 0, bytesRead); 408 } 409 } 410 411 private static String join(AbstractCollection<String> col, String delimiter) { 412 if (col.isEmpty()) return ""; 413 Iterator<String> iter = col.iterator(); 414 StringBuffer buffer = new StringBuffer(iter.next()); 415 while(iter.hasNext()) buffer.append(delimiter).append(iter.next()); 416 return buffer.toString(); 417 } 418 419 private String getBaseUri() { 420 if (m_useSSL) 421 { 422 return String.format("https://%s:%d/api/", api_hostname, API_HTTPS_PORT); 423 } 424 else 425 { 426 return String.format("http://%s:%d/api/", api_hostname, API_HTTP_PORT); 427 } 428 } 429 430 private HttpURLConnection getConnection(String uriSuffix, String contentType) throws IOException { 431 try 432 { 433 URL url; 434 HttpURLConnection conn = (HttpURLConnection)new URL( 435 getBaseUri() + uriSuffix).openConnection(); 436 437 if (m_useSSL) 438 { 439 // BUG: sun-java6-bin: missing cacerts the trustAnchors parameter must be non-empty 440 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=564903 441 HttpsURLConnection ssl_conn = (HttpsURLConnection)conn; 442 ssl_conn.setHostnameVerifier(HOSTNAME_VERIFIER); 443 } 444 conn.setRequestMethod("POST"); 445 conn.setDoOutput(true); 446 conn.setRequestProperty("Content-Type", contentType); 447 conn.setConnectTimeout(120000); 448 return conn; 449 } 450 catch(MalformedURLException e) 451 { 452 throw new PdfcrowdError(e); 453 } 454 } 455 456 private void callAPI(Object data, String uriSuffix, 457 OutputStream outStream, String contentType) { 458 try 459 { 460 HttpURLConnection conn = getConnection(uriSuffix, contentType); 461 OutputStream wr = conn.getOutputStream(); 462 if (data instanceof byte[]) { 463 //System.out.println(new String((byte[])data)); 464 wr.write((byte[])data); 465 } 466 else { 467 //System.out.println(((ByteArrayOutputStream)data).toString()); 468 ((ByteArrayOutputStream)data).writeTo(wr); 469 } 470 wr.flush(); 471 472 if (conn.getResponseCode() == 200) { 473 InputStream rd = conn.getInputStream(); 474 copyStream(rd, outStream); 475 rd.close(); 476 } 477 else { 478 String errMsg; 479 if (conn.getErrorStream() != null) { 480 ByteArrayOutputStream errOut = new ByteArrayOutputStream(); 481 copyStream(conn.getErrorStream(), errOut); 482 errMsg = errOut.toString(); 483 } 484 else { 485 errMsg = conn.getResponseMessage(); 486 } 487 throw new PdfcrowdError(errMsg, conn.getResponseCode()); 488 } 489 wr.close(); 490 } 491 catch(IOException e) 492 { 493 throw new PdfcrowdError(e); 494 } 495 } 496 497 private ByteArrayOutputStream encodeMultipartPostData(String filename) { 498 try 499 { 500 Vector<String> body = new Vector<String>(); 501 Iterator<String> it = fields.keySet().iterator(); 502 ByteArrayOutputStream retval = new ByteArrayOutputStream(); 503 while(it.hasNext()) { 504 String key = it.next(); 505 String val = fields.get(key); 506 if (val != null) 507 { 508 body.add("--" + MULTIPART_BOUNDARY); 509 body.add(String.format("Content-Disposition: form-data; name=\"%s\"", key)); 510 body.add(""); 511 body.add(val); 512 } 513 } 514 // filename 515 body.add("--" + MULTIPART_BOUNDARY); 516 body.add(String.format("Content-Disposition: form-data; name=\"src\"; filename=\"%s\"", filename)); 517 body.add("Content-Type: application/octet-stream"); 518 body.add(""); 519 body.add(""); 520 retval.write(join(body, "\r\n").getBytes("UTF-8")); 521 body.clear(); 522 523 // read file 524 copyStream(new FileInputStream(filename), retval); 525 526 body.add(""); 527 body.add("--" + MULTIPART_BOUNDARY); 528 body.add(""); 529 retval.write(join(body, "\r\n").getBytes("UTF-8")); 530 531 return retval; 532 } 533 catch(UnsupportedEncodingException e) { 534 throw new PdfcrowdError(e); 535 } 536 catch(IOException e) { 537 throw new PdfcrowdError(e); 538 } 539 } 540 541 542 private byte[] encodePostData(String src) { 543 544 Vector<String> body = new Vector<String>(); 545 Iterator it = fields.keySet().iterator(); 546 try 547 { 548 if (src != null) 549 body.add(URLEncoder.encode("src", "UTF-8") + "=" + 550 URLEncoder.encode(src, "UTF-8")); 551 552 while(it.hasNext()) { 553 Object key = it.next(); 554 Object val = fields.get(key); 555 556 if (val != null) 557 { 558 body.add(URLEncoder.encode(key.toString(), "UTF-8") + "=" + 559 URLEncoder.encode(val.toString(), "UTF-8")); 560 } 561 } 562 return join(body, "&").getBytes("UTF-8"); 563 } 564 catch(UnsupportedEncodingException e) 565 { 566 throw new PdfcrowdError(e); 567 } 568 } 569 }