Total Pageviews

2016/07/03

[PDFBox] Warning: You did not close a PDF Document

Problem
I am using PDFBox to covert a PDF file to TIF file. 


But getting warning message as I do PDF to TIF conversion:
1
[WARN][Finalizer][Line:481][org.apache.pdfbox.cos.COSDocument.finalize]Warning: You did not close a PDF Document


Code snippet looks like:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 // 產TIF
 private List<String> generateTifFile(TifConversionParam params, String filePath)
          throws IOException {

      List<String> rs = null;
      PDDocument document = null;
      try {
          document = PDDocument.load(new File(params.getFile()));
          String policyNumber = params.getPolicyNumber();
          rs = writeImage(document, filePath + policyNumber, ImageType.BINARY, DPI, policyNumber);
      } catch (IOException e) {
          throw new RuntimeException(e);
      } 

      return rs;
  }

  private List<String> writeImage(PDDocument document, String outputPrefix, ImageType imageType,
          float dpi, String fileName) throws IOException {
      List<String> tifNames = new ArrayList<String>();
      PDFRenderer renderer = new PDFRenderer(document);

      for (int i = 0; i < document.getNumberOfPages(); i++) {
          BufferedImage image = renderer.renderImageWithDPI(i, dpi, imageType);

          String outputPostfix = "_" + String.format("%02d", i + 1); // 01開始
          String outputFileName = outputPrefix + outputPostfix;// 檔名: 保單號碼_0X

          tifNames.add(fileName + outputPostfix); // 回傳產了那些檔名

          ImageIOUtil.writeImage(image, outputFileName + "." + "tif", Math.round(dpi));
          image.flush();
      }
      return tifNames;
  }


Solution
You need to call close() on the PDDocument inside the finally block, if you don't then the document will not be closed properly. Also, you must close all PDDocument objects that get created. 


Updated code snippet looks like:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 產TIF
 private List<String> generateTifFile(TifConversionParam params, String filePath)
          throws IOException {

      List<String> rs = null;
      PDDocument document = null;
      try {
          document = PDDocument.load(new File(params.getFile()));
          String policyNumber = params.getPolicyNumber();
          rs = writeImage(document, filePath + policyNumber, ImageType.BINARY, DPI, policyNumber);
      } catch (IOException e) {
          throw new RuntimeException(e);
      } finally {
          if (document != null) {
              document.close();
          }
      }

      return rs;
  }

  private List<String> writeImage(PDDocument document, String outputPrefix, ImageType imageType,
          float dpi, String fileName) throws IOException {
      List<String> tifNames = new ArrayList<String>();
      PDFRenderer renderer = new PDFRenderer(document);

      for (int i = 0; i < document.getNumberOfPages(); i++) {
          BufferedImage image = renderer.renderImageWithDPI(i, dpi, imageType);

          String outputPostfix = "_" + String.format("%02d", i + 1); // 01開始
          String outputFileName = outputPrefix + outputPostfix;// 檔名: 保單號碼_0X

          tifNames.add(fileName + outputPostfix); // 回傳產了那些檔名

          ImageIOUtil.writeImage(image, outputFileName + "." + "tif", Math.round(dpi));
          image.flush();
      }
      return tifNames;
  }  


Reference
[1] https://pdfbox.apache.org/1.8/faq.html#notclosed

2016/07/02

[閱讀筆記] ZERO to ONE (Part 1)



  1. 進步有分成兩種形式,第一種是水平的進步,這種進步是複製已經成功的方法,也就是從1到n,如從1台打字機生產出100台打字機;第二種是垂直的進步,這種進步是開發新的事物,也就是從0到1,如從1台打字機做出1台文書處理機。
  2. 全球化的發展,是水平的進步,如現在的中國,將今日美國等已開發國家成功的事物,複製到中國;科技的發展,是垂直的進步,如這幾十年來資訊科技的快速發展。
  3. 天才雖然可以獨力完成經典的藝術或文學作品,卻不能獨立創造整個產業。新創事業的運作原則,就是必須和其他人合作完成工作,而且組織要小到能讓所有事情順利運作
  4. 尼采曾說:瘋狂少見於個人,但在團體、政黨、國家、時代來說,卻是常態
  5. 保持思路清晰的首要步驟,就是質疑自己
  6. 在完全競爭下,長期來看,沒有公司可以得到經濟利潤 (economic profit)
  7. 如果想要創造並長久留住價值,你就不應該建立一個沒有差異化的產品模式
  8. 創業家對競爭態勢總是輕描淡寫,但那是新創事業會犯下的最大錯誤。創業家的致命誘惑,是把市場描述得很窄,表現出掌握大局的樣子
  9. 非獨占者常把自己所在的市場,定義為很多小市場的交集,用來誇大自身的獨特性;獨佔者會掩飾自己的獨佔地位,把他們的市場描述成幾個大市場的聯集,避免被政府盯上
  10. 獨佔者才能思考賺錢以外的事情,非獨占者不能。在完全競爭下,企業會專注在今天的利潤,所以無法規劃長遠的未來。只有一件事可以讓企業超越求生的日常殘酷廝殺,那就是取得獨佔利潤
  11. 人類的進步史,就是用更好的獨佔事業取代舊的獨佔事業的歷史
  12. 獨佔可以讓發明持續,因為利潤讓它們得以擬定長期計畫,投資在競爭公司無法想像、野心勃勃的研發計畫
  13. 幸福的家庭全都非常相似,不幸的家庭各有不幸。企業恰恰相反,成功的企業長的都不一樣,每家公司靠解決一個獨特的問題而贏得獨占地位;倒閉的企業則都一樣,無法從競爭中脫穎而出。
  14. 用模仿當競爭手段很危險,這就是為什麼亞斯伯格症這種拙於社交的人在矽谷佔有優勢,因為這些人對社會線索沒有那麼敏感,比較不會和身邊的人做一樣的事情
  15. 擺脫競爭可以取得獨佔,但獨佔的企業也要屹立不搖才了不起
  16. 一個偉大的事業應該從未來產生現金流的能力來定義
  17. 企業今天的價值是未來能賺到的錢的總和,因此,想要適當估計企業的價值,必須把未來現金流折算為現在的價值,因為今天的錢比未來還有價值
  18. 一家有價值的企業,不但必須成長,還必須能夠持續成長
  19. 貼現現金流(discounted cash flow)的比較,可以彰顯出低成長企業和高成長新創事業的差異。低成長企業的貼現現金流,隨的時間越長越來越萎縮;高成長新創企業,初期常常虧錢,隨著打造出有價值的服務或商品後,貼現現金流逐漸攀升
  20. 根據經驗法則,重點的專利技術要比最接近的替代品好10倍以上,才能取得真正的獨佔優勢。如果不到10倍,可能會被視為微幅改善,這樣的產品很難賣得出去,特別是在已經很壅擠的市場。要比別人進步10倍以上,最簡單的方法是發明全新的產品,如果能端出過去沒有的有價值產品,其增加的價值理論上是無窮大
  21. 網路外部性或稱為網路效應(Network Effects),對個別消費者而言,一項產品價值取決於市場整體的使用人數;因此該產品的使用者或用戶人數越多,對新的加入者的價值或效益就越高,因此越具吸引力。
  22. 沒有科技公司可以僅靠品牌吃飯,靠品牌而不靠實力來經營,是一件很危險的事情
  23. 獨佔 = 專利技術 + 網路外部性 + 經濟規模 + 品牌
  24. 每個新創事業都應該由非常小的市場開始,要錯也是錯在起步的規模太小。一個大市場不是欠缺好的起跑點,就是處在開放競爭的狀態,連要搶下1%的市占率都很難。
  25. 最成功的企業會先佔據一個特定的利基市場,然後擴展到相近的市場。成功的企業都有個類似的故事,他們都是由核心事業逐步向外擴展

2016/07/01

[閱讀筆記] Security Analysis (Part 1)


  1. 所謂的安全邊際(margin of safety),是指容許錯誤、失誤、壞運氣或是經濟與股市上下震盪的空間
  2. 所謂的價值投資(Value Investment),就是在此檔股票的價格低於其真實價值時,買進此檔股票。但其不僅僅是於便宜價格買進而已,還要做深度的分析、追求長期的投資成果、限制與管理風險,並克制從眾心理。
  3. 藝術品、稀有郵票、酒等等的投資,都屬於投機,不是投資。因為這些東西都沒有有根據的基本價值,一切都根據買方願意花多少錢來買
  4. Value investor 聚焦於追求長期投資的效益,不會希望透過每日頻繁交易來獲利
  5. 短期的貪婪與恐懼的力量,是造成價格與真實價值悖離的主因
  6. Value investor 的特色是:耐性、有紀律、規避風險(risk aversion)
  7. 根據研究顯示,價格便宜的股價表現會優於昂貴的股票(用帳面價值比、本益比或殖利率來衡量);最近三、五年表現不好的股票,接下來的表現會優於近期表現良好的股票
  8. 許多學院派的分析理論,常常把真實世界過度簡化,導致其分析預測的結果有誤。這些理論有一個錯誤的假設,人在投資決策時是理性的,但是實際上,就是因為不理性的人性,導致市場失序與價格偏誤
  9. 當成長不如預期,投資人該怎麼做? 希望能恢復過去股價? 放棄並賣出? 喪失成長動能的股票會被大舉拋售,如2002年的dot com泡沫,一堆科技股的價格跌到不可思議的低價,這時其實就是value investor進場的時機,那都是夢寐以求的價位
  10. 學院派認為,從歷史的資料來看,變動性越大的股票,風險越大。但是,身為一個value investor,應把風險視為你可能損失的金額,你要衡量,若損失這樣的金額,你能否承受。事實上,一個高變動性的股票,價格也有可能被嚴重低估,變成一個低風險的投資
  11. 不要一直想著迅速致富,你應該想的是:控制風險與限制損失
  12. 在SecurityAnalysis中所提到的intrinsic value(真實價值),是指根據真實所定義的價值,如公司資產、營收、股利、明確的未來展望等
  13. 購買高收益債券要注意,不要被其高收益的部分所蒙蔽,有時候資本損失的金額,可能還無法被所分配的收益所cover
  14. Good stock的定義,有兩種: (1) 位居產業龍頭,營收表現佳,此種企業在未來比較能有令人滿意的營收、(2) 企業財務健全,其在未來比較有可能有好的表現。可口可樂屬於(1)、雅培屬於(2)、GE屬於(1)(2)
  15. 沒有所謂的正確的本益比。在1937年GE的股票漲到64,隔年跌到27,一切端視市場氣氛是樂觀或是悲觀,這些價格都是投資者決定的投資價值或投資估價
  16. 許多有投機心態的投資人,就像剛拿到駕照就急著要開家人車子的年輕人一樣,他不會想把車子撞壞,但是避免發生意外不是最重要的事情,因為他不認為意外會發生在他身上
  17. 所謂的investment,是指"promise safety of pincipal and satisfactory return" (有較高的勝算與令人滿意的回報)
  18. 在預測股價未來表現上,帳面價值 (book vale) 幾乎是沒有用的
  19. 在預測企業未來營收上,Security Analysis提供兩個原則:(1) 營收波動較大的公司,在預測上要越小心,你最好要研究這家公司過去十年來的表現;(2) 要用近幾年的平均營收來做為預測的粗略的指引,不要用營收的趨勢,趨勢是不可靠的
  20. 當一家公司的損益表(Income Statement) 與現金流量表(Cash Flow Statement) 對不起來的時候,你就要注意了。如當一家公司不斷提到營收創新高,但是從現金流量表卻看不到現金流進來,這時你應該盡快遠離
  21. 從損益表(Income Statement)可以看出企業的獲利狀況;從現金流量表(Cash Flow Statement)可以看出錢的流動
  22. 分析工作的失敗,主要來自:(1)不適當或不正確的資料;(2)未來的不確定性;(3)市場中不合理的行為
  23. security analysis是利用過去的紀錄作為假設與前提,來預測未來。當這個假設的問題越多,分析結果就越不可靠。當股票的價格變動越大,分析結果就越容易失準
  24. 股票市場不是一個weighing machine,其沒有一個精確與客觀的機制來判斷這檔股票的合理價位;股票市場比較像是voting machine,散戶們憑藉著自己的感覺、情感與推論,進行投票
  25. 這檔股票是否可以買/賣/繼續持有。這個問題就包含security analysis的四個元素:security、price、time與person。如某人(person)的股票(security),在現在(time)的價位(price),應如何
  26. 記住,你所使用的分析方法與原則,必須能適用於大部分的狀況,若只適用於特定狀況,那麼你這個方法是無效的
  27. 對於未經訓練的投資人,不要把你的錢拿去買低評等企業的股票
  28. 未經訓練的投資人,Graham建議購買評等較佳的公司的股票。但這不代表完全沒有的損失的風險,只是相較於低評等的企業,其比較safe
  29. 對於受過訓練的投資人,要注意這個價格在此波段可能是便宜的價位,但是在另一個波段卻是昂貴的價位
  30. 在做business analysis的時候要注意,專利的保護、地理的優勢、勞動成本等等的優勢,都是無法持久的
  31. Quantitative Analysis (定量分析)提供了公司的統計分析結果,如資產負債表、現金流量表等等,這些資訊包含 (1) 資本額、(2) 營收與股利、(3)資產與負債、(4) 營運統計數字
  32. Qualitative Analysis (定性分析) 主要是在研究企業的本質,如某間企業在該產業中的排名的相對位置、管理階層的特質、企業未來展望、企業所處產業的未來展望等等
  33. 廣義來說,Quantitative Analysis(定量分析)的資料較容易取得、且較可靠,也較容易形成精確與可靠的結論。Security analysis會把定性分析的結果當做企業的簡介,大部分的分析結果還是會根據定量分析所提供的數字
  34. 異常的好或異常的壞的狀況,不會永遠持續,市場總是有一股修正的力量,會將其修正的適當的位置 
  35. 根據過去的資料所分析出來的營收趨勢是fact(事實),然而跟去過去所推測未來趨勢的資料只是assumption(假設)


2016/06/09

[WAS] WSVR0605W - "Thread may be hung"

Problem
I'm running my web application on IBM WebSphere.
There is a warning message in System.out.log :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[4/25/16 17:16:03:756 CST] 00000068 SystemOut     O [2016-04-25 17:16:03][WARN][Deferrable Alarm : 1][Line:1709][com.ibm.ws.runtime.component.ThreadMonitorImpl.logToJSR47Logger]WSVR0605W: Thread "WebContainer : 6" (000000d3) has been active for 667,910 milliseconds and may be hung.  There is/are 1 thread(s) in total in the server that may be hung.
    at java.io.RandomAccessFile.readBytes(Native Method)
    at java.io.RandomAccessFile.read(RandomAccessFile.java:368)
    at org.apache.fontbox.ttf.BufferedRandomAccessFile.fillBuffer(BufferedRandomAccessFile.java:122)
    at org.apache.fontbox.ttf.BufferedRandomAccessFile.read(BufferedRandomAccessFile.java:160)
    at org.apache.fontbox.ttf.RAFDataStream.read(RAFDataStream.java:162)
    at org.apache.fontbox.ttf.TTFDataStream.read(TTFDataStream.java:263)
    at org.apache.fontbox.ttf.TTFDataStream.readString(TTFDataStream.java:91)
    at org.apache.fontbox.ttf.TTFDataStream.readString(TTFDataStream.java:64)
    at org.apache.fontbox.ttf.TTFParser.readTableDirectory(TTFParser.java:232)
    at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:139)
    at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:87)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.addTrueTypeFont(FileSystemFontProvider.java:502)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.scanFonts(FileSystemFontProvider.java:246)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.<init>(FileSystemFontProvider.java:225)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl$DefaultFontProvider.<clinit>(FontMapperImpl.java:132)
    at java.lang.J9VMInternals.initializeImpl(Native Method)
    at java.lang.J9VMInternals.initialize(J9VMInternals.java:236)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getProvider(FontMapperImpl.java:151)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.findFont(FontMapperImpl.java:415)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getTrueTypeFont(FontMapperImpl.java:323)
    at org.apache.pdfbox.pdmodel.font.PDTrueTypeFont.<init>(PDTrueTypeFont.java:198)
    at org.apache.pdfbox.pdmodel.font.PDFontFactory.createFont(PDFontFactory.java:75)
    at org.apache.pdfbox.pdmodel.PDResources.getFont(PDResources.java:123)
    at org.apache.pdfbox.contentstream.operator.text.SetFontAndSize.process(SetFontAndSize.java:60)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processOperator(PDFStreamEngine.java:815)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processStreamOperators(PDFStreamEngine.java:472)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processStream(PDFStreamEngine.java:446)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processPage(PDFStreamEngine.java:149)
    at org.apache.pdfbox.rendering.PageDrawer.drawPage(PageDrawer.java:189)
    at org.apache.pdfbox.rendering.PDFRenderer.renderPage(PDFRenderer.java:208)
    at org.apache.pdfbox.rendering.PDFRenderer.renderImage(PDFRenderer.java:139)
    at org.apache.pdfbox.rendering.PDFRenderer.renderImageWithDPI(PDFRenderer.java:94)

And my function is hung after I click execute button.


How-to
You need to log into WAS administration console, then go to Servers > Application Servers > server_name. Click Administration > Custom Properties Under Server Infrastructure.

And add four arbitrates

  • com.ibm.websphere.threadmonitor.interval: 180
  • com.ibm.websphere.threadmonitor.threshold: 600
  • com.ibm.websphere.threadmonitor.false.alarm.threshold: 100
  • com.ibm.websphere.threadmonitor.dump.java: false



Remember to save attributes and restart WAS.

But this is just a workaround solution, it may means your programs may consume lots of memory for some reasons. You still need to figure out its root causes and fix them.


Reference
[1] http://websphere-solutions.blogspot.tw/2011/10/hung-threads.html

2016/06/08

[AngularJS] How to add tooltips in ng-grid

Problem
I implemented a data grid by ng-grid as bellows:


The problem is if the length of data is larger than the width of column, it will show ... then ignore the rest of information. Our customer requests to show complete information in tooltips as he/she move cursor on it.

The code snippet of ng-grid looks like:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$scope.gridCols  = [ 
 {
     field : 'sourceName',
     width : '10%',
     displayName : '來源系統',
     cellClass : 'text-left'
 }, {
     field : 'policyNumber',
     width : '10%',
     displayName : '保單號碼',
     cellClass : 'text-left'
 },{
     field : 'exeMsg',
     width : '65%',
     displayName : '執行訊息',
     cellClass : 'text-left'
 },{
     field : 'exeTime',
     width : '15%',
     displayName : '執行時間',
     cellFilter : "date:'yyyy-MM-dd HH:mm:ss'",
     cellClass : 'text-left'
 }];
 
 $scope.dataGrid = {
     multiSelect : false,
     data : 'itemData',
     columnDefs : 'gridCols',
     enableColumnResize: true,
     enableRowSelection: true,
     rowHeight : 40
 };


How-to
There has two steps to fulfill this requirement.
Step 1. add css in HTML page
1
2
3
4
5
6
7
   <style type="text/css">
    .tooltip-inner {
      text-align: left;
      white-space: pre-wrap;
      max-width: none;
    }
    </style>

Step 2. Modify the ng-grid, and add cellTemplate to show complete information
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 var exeMsgCellTemplate='<span tooltip="{{row.entity.exeMsg}}" tooltip-append-to-body="true" tooltip-trigger:"focus"><div style="vertical-align : middle;"  class="ngCellText">{{row.entity.exeMsg}}</div></span>';
 var exeTimeCellTemplate='<span tooltip="{{row.entity.exeTime|date:\'yyyy-MM-dd HH:mm:ss\'}}" tooltip-append-to-body="true" tooltip-trigger:"focus"><div style="vertical-align : middle;"  class="ngCellText">{{row.entity.exeTime|date:\'yyyy-MM-dd HH:mm:ss\'}}</div></span>';
               
 $scope.gridCols  = [ 
 {
     field : 'sourceName',
     width : '10%',
     displayName : '來源系統',
     cellClass : 'text-left'
 }, {
     field : 'policyNumber',
     width : '10%',
     displayName : '保單號碼',
     cellClass : 'text-left'
 },{
     field : 'exeMsg',
     width : '65%',
     displayName : '執行訊息',
     cellClass : 'text-left',
     cellTemplate : exeMsgCellTemplate
 },{
     field : 'exeTime',
     width : '15%',
     displayName : '執行時間',
     cellFilter : "date:'yyyy-MM-dd HH:mm:ss'",
     cellClass : 'text-left',
     cellTemplate : exeTimeCellTemplate
 }];
 
 $scope.dataGrid = {
     multiSelect : false,
     data : 'itemData',
     columnDefs : 'gridCols',
     enableColumnResize: true,
     enableRowSelection: true,
     rowHeight : 40
 };



Check the result:





Reference
[1] http://www.w3schools.com/cssref/pr_text_white-space.asp



2016/06/07

[PDFBox] Utilize Apache PDFBox to Convert PDF to TIF

Requirement
We have an requirement to convert a PDF file to TIF file(s). 
If PDF has 3 pages, it should generate 3 TIF files with 300 DPI. 
For instance, a Getting Started.pdf has 4 pages,it should convert to 4 TIF files, including Getting Started.pdf_01.tifGetting Started.pdf_02.tifGetting Started.pdf_03.tif, and Getting Started.pdf_04.tif.


How-to
We can utilize Apache PDFBox to fulfill this requirement.

You should add maven dependency in your pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox-tools</artifactId>
            <version>2.0.0</version>
        </dependency>
        
        <dependency>
            <groupId>com.github.jai-imageio</groupId>
            <artifactId>jai-imageio-core</artifactId>
            <version>1.3.1</version>
        </dependency>


Sample code looks like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package albert.practice.file;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import lombok.extern.slf4j.Slf4j;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;

@Slf4j
public class PdfFileToTif {

    private final float dpi = 300f;

    public static void main(String[] args) {
        File pdfFile = new File("D:\\dropbox\\Getting Started.pdf");
        String destination = "D:\\dropbox\\";

        PdfFileToTif test = new PdfFileToTif();
        test.convertPdfToTif(pdfFile, destination);
    }

    public void convertPdfToTif(File pdfFile, String destination) {
        if (!isFileExisted(pdfFile)) {
            throw new RuntimeException("File not found ! (" + pdfFile.getAbsolutePath() + ")");
        }

        String pdfFileName = pdfFile.getName();

        try {
            // load PDF document
            PDDocument document = PDDocument.load(pdfFile);

            // create PDF renderer
            PDFRenderer renderer = new PDFRenderer(document);

            // go through each page of PDF, and generate TIF for each PDF page.
            for (int i = 0; i < document.getNumberOfPages(); i++) {
                // Returns the given page as an RGB image with 300 DPI.
                BufferedImage image = renderer.renderImageWithDPI(i, dpi, ImageType.BINARY);

                // Assign the file name of TIF
                String fileName = pdfFileName + "_" + String.format("%02d", i + 1);
                log.debug("Generating  " + fileName + ".tif to " + destination);

                // Writes a buffered image to a file using the given image format.
                ImageIOUtil.writeImage(image, destination + fileName + ".tif", Math.round(dpi));
                image.flush();
            }
            log.debug("PDF to TIF conversion well done!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 判斷檔案是否存在
     * 
     * @param file
     * @return true - 檔案存在; false - 檔案不存在
     */
    private Boolean isFileExisted(File file) {
        Boolean isExisted = Boolean.FALSE;
        isExisted = (file.exists() && (!file.isDirectory()));
        return isExisted;
    }

}


Reference
[1] https://pdfbox.apache.org/