반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

오늘은 PDF 파일에 있는 내용을 가져와서 브라우저에 텍스트로 뿌려 주는 것을 공부해 보겠습니다.

저희가 만든 웹앱에 식당 메뉴를 제공하려고 하는데요.
식당을 운영하는 회사에서 메뉴를 PDF 형식으로 그 회사 웹에서 제공하고 있어요.


그런데 회사사람들 대부분이 블랙베리 폰을 사용하고 있어서 구형 BB 에서는 PDF 형식을 보여주기가 힘들거든요.


그 회사랑 따로 EDI 시스템 개발해서 데이터 주고 받고 하는 번거로운일을 하지 않고 그냥 그 회사에서 제공하는 메뉴에서 우리가 필요한 데이터만 추출해서 서비스하는 방법을 고민중입니다.


일단 인터넷 서핑을 통해서 PDF 를 TEXT 로 바꿔주는 소스코드는 구했습니다.

이 소스코드를 한번 분석해 보고 어떤 방법이 있을지 없을지 알아보려구요.




메뉴는 이렇게 생긴 PDF 파일인데요.

왼쪽의 내용들은 필요 없고 오른쪽에 있는 요일별 메뉴들만 뽑고 싶거든요.


원본 pdf 파일과 이 내용을 text 로 바꿔주는 PHP 파일은 여기 있습니다.



original.pdf

pdf2text.php


이걸 돌리면 결과가 아래와 같이 나옵니다.



흠 다 텍스트로 나오긴 나왔는데 이거 가지고는 따로 메뉴만 추출해 내기 쉽지 않네요.

이렇게 모두 한줄로 나오는게 아니라 라인별로 따로 출력이 돼면 좀 더 낫지 않을까요?


일단 pdf2text.php 를 분석해 봐야 겠습니다.


pdf2text.php 파일 안에는 9개의 함수가 있습니다.



이 pdf2text.php 를 실행하면 제일 먼저 어떤게 실행될까요?

함수들은 어디서 호출을 해 줘야 실행되니까 다 그냥 건너뛰겠고...

$result = pdf2text ('original.pdf'); 가 제일 먼저 실행되겠죠?


이건 pdf2text($filename) 함수를 call 하는 겁니다. 거기서 처리된 값을 $result 변수에 담고 그 내용을 echo 함수로 브라우저에 뿌려주는게 이 프로그램이 하는일의 전부 다 입니다.


이제 그 중간의 처리 과정을 자세히 공부해 보겠습니다.


우선 pdf2text($filename) 함수는 아래와 같습니다.


function pdf2text($filename) {
// file_get_contents return the contents of a file as a string
    $infile = @file_get_contents($filename, FILE_BINARY);
    if (empty($infile))
        return "";

    $transformations = array();
    $texts = array();

    preg_match_all("#obj(.*)endobj#ismU", $infile, $objects);
    $objects = @$objects[1];
   
   

    for ($i = 0; $i < count($objects); $i++) {
        $currentObject = $objects[$i];
//echo $currentObject . "<p> end";
        if (preg_match("#stream(.*)endstream#ismU", $currentObject, $stream)) {
            $stream = ltrim($stream[1]);
//echo $stream . "<p> end";
            $options = getObjectOptions($currentObject);
            if (!(empty($options["Length1"]) && empty($options["Type"]) && empty($options["Subtype"])))
                continue;

            $data = getDecodedStream($stream, $options);
            if (strlen($data)) {
                if (preg_match_all("#BT(.*)ET#ismU", $data, $textContainers)) {
                    $textContainers = @$textContainers[1];
                    getDirtyTexts($texts, $textContainers);
                } else
                    getCharTransformations($transformations, $data);
            }
        }
    }

    return getTextUsingTransformations($texts, $transformations);
}

맨 처음으로는 해당 파일의 내용을 받아옵니다. 이것은 바이너리 형식이라서 사람이 읽을 수 있는건 아닙니다. ($infile = @file_get_contents($filename, FILE_BINARY);)

그 내용을 출력해 보면 아래와 같이 나옵니다.



이걸 보면 헤더정보만 사람이 읽을 수 있는 텍스트죠?

이 문서는 PDF 1.5 버전이라는 것을 알 수 있습니다.

그리고 이 헤더정보는 endobj 부분에서 끝나는 겁니다.
나머지는 사람이 읽을 수 없는 바이너리 형식입니다.

그 다음 if 문에서는 해당 파일이 비어있는건지 봅니다. 비어있으면 나머지 로직을 실행할 필요가 없겠죠? 괜히 시간만 낭비니까 그 cost 를 줄이기 위해 비어있으면 그냥 return 을 해 버립니다.


파일이 empty 가 아니면 그 다음을 실행할 텐데요.

(참고로 if 문의 {} 가 없습니다. 그 안에 내용이 단 1줄이면 {} 없이 사용할 수 있습니다.

그러면 바로 그 다음줄까지만 if 절 안에 포함돼 있는 겁니다.)


그 다음은 $transformations 라는 배열과 $texts 라는 배열을 만들어 줍니다.


오늘은 여기까지만 하고 다음에 계속 분석해 보겠습니다.

지금 토요일 아침 7시 40분인데요.

가족이랑 어디 가기로 해서 지금 나가봐야 되네요.


여행 다녀와서 계속 공부할텐데 그 내용도 여기 정리해 놓을께요.



반응형