오늘의하루

OpenPDF 기여 활동 본문

JAVA/OpenSource 기여활동

OpenPDF 기여 활동

오늘의하루_master 2024. 4. 11. 09:53

OpenPDF란?

OpenPDF란 Java로 작성된 PDF를 처리하는 라이브러리 입니다. 

PDF 문서를 생성, 편집, 읽기 및 조작할 수 있는 기능을 제공하여 자바 애플리케이션에서 PDF 관련 작업을 수행하는 데 도움을 줍니다.

활동을 하게 된 계기

PDF 처리를 위해 기존에는 PDFBox를 사용하고 있었습니다. 그러던 중 PDFBox의 내부 코드를 더 자세히 살펴보고 싶어졌고, 이를 통해 코드를 보며 학습하는 기회를 얻었습니다. 그러던 중 OpenPDF 라이브러리를 발견했고, PDFBox에는 없는 기능들이 있을지 궁금해졌습니다. 또한, 최근에는 유지보수성과 코드의 가독성을 높이는 것에 관심이 많았는데, 이를 이론적인 수준에서만이 아니라 실제 프로젝트에 적용하여 검증받고 싶어졌습니다. 그래서 OpenPDF에 기여하게 되었습니다.

OpenSource에 기여한 내용 - 1

// 기존 코드
private Comparator<Entry> comparator = (en1, en2) -> {
    int rt = 0;
    if (en1.getIn1() != null && en2.getIn1() != null) {
        if ((rt = en1.getIn1().compareToIgnoreCase(en2.getIn1())) == 0) {
            if (en1.getIn2() != null && en2.getIn2() != null) {
                if ((rt = en1.getIn2()
                        .compareToIgnoreCase(en2.getIn2())) == 0) {
                    if (en1.getIn3() != null && en2.getIn3() != null) {
                        rt = en1.getIn3().compareToIgnoreCase(
                                en2.getIn3());
                    }
                }
            }
        }
    }
    return rt;
};


// 수정 후 코드
private Comparator<Entry> comparator = (en1, en2) -> {
    int rt = compareStringsIgnoreCase(en1.getIn1(), en2.getIn1());
    if (rt != 0) {
        return rt;
    }
    rt = compareStringsIgnoreCase(en1.getIn2(), en2.getIn2());
    if (rt != 0) {
        return rt;
    }
    return compareStringsIgnoreCase(en1.getIn3(), en2.getIn3());
};

private int compareStringsIgnoreCase(String str1, String str2) {
    if (str1 == null || str2 == null) {
        return 0;
    }
    return str1.compareToIgnoreCase(str2);
}


이 코드의 수정 이유는 가독성을 향상시키고 중복 코드를 제거하여 유지보수를 쉽게 하기 위함입니다. 기존 코드는 중첩된 if 문으로 인해 가독성이 낮았으며, 각 문자열을 비교할 때마다 중복되는 로직이 사용되었습니다. 수정 후 코드는 compareStringsIgnoreCase 메소드를 도입하여 각 문자열 비교를 일관되고 간결하게 처리하였습니다. 이로 인해 코드의 가독성이 향상되었고, 중복 코드가 제거되어 유지보수가 용이해졌습니다.

OpenSource에 기여한 내용 - 2

// 기존 코드
private void Fax3Encode2DRow() {
    int a0 = 0;
    int a1 = (pixel(dataBp, offsetData, 0) != 0 ? 0 : finddiff(dataBp, offsetData, 0, rowpixels, 0));
    int b1 = (pixel(refline, 0, 0) != 0 ? 0 : finddiff(refline, 0, 0, rowpixels, 0));
    int a2, b2;

    for (; ; ) {
        b2 = finddiff2(refline, 0, b1, rowpixels, pixel(refline, 0, b1));
        if (b2 >= a1) {
            int d = b1 - a1;
            if (!(-3 <= d && d <= 3)) {    /* horizontal mode */
                a2 = finddiff2(dataBp, offsetData, a1, rowpixels, pixel(dataBp, offsetData, a1));
                putcode(horizcode);
                if (a0 + a1 == 0 || pixel(dataBp, offsetData, a0) == 0) {
                    putspan(a1 - a0, TIFFFaxWhiteCodes);
                    putspan(a2 - a1, TIFFFaxBlackCodes);
                } else {
                    putspan(a1 - a0, TIFFFaxBlackCodes);
                    putspan(a2 - a1, TIFFFaxWhiteCodes);
                }
                a0 = a2;
            } else {            /* vertical mode */
                putcode(vcodes[d + 3]);
                a0 = a1;
            }
        } else {                /* pass mode */
            putcode(passcode);
            a0 = b2;
        }
        if (a0 >= rowpixels) {
            break;
        }
        a1 = finddiff(dataBp, offsetData, a0, rowpixels, pixel(dataBp, offsetData, a0));
        b1 = finddiff(refline, 0, a0, rowpixels, pixel(dataBp, offsetData, a0) ^ 1);
        b1 = finddiff(refline, 0, b1, rowpixels, pixel(dataBp, offsetData, a0));
    }
}


// 수정 후 코드
private void Fax3Encode2DRow() {
    int a0 = 0;
    int a1 = (pixel(dataBp, offsetData, 0) != 0 ? 0 : finddiff(dataBp, offsetData, 0, rowpixels, 0));
    int b1 = (pixel(refline, 0, 0) != 0 ? 0 : finddiff(refline, 0, 0, rowpixels, 0));
    int a2, b2;

    for (;;) {
        b2 = finddiff2(refline, 0, b1, rowpixels, pixel(refline, 0, b1));
        int d = b1 - a1;

        if (b2 >= a1 && !(-3 <= d && d <= 3)) { 
            a2 = finddiff2(dataBp, offsetData, a1, rowpixels, pixel(dataBp, offsetData, a1));
            handleHorizontalMode(a0, a1, a2);
            a0 = a2;
        } else if (b2 >= a1) { 
            putcode(vcodes[d + 3]);
            a0 = a1;
        } else { 
            putcode(passcode);
            a0 = b2;
        }
        if (a0 >= rowpixels) {
            break;
        }
        a1 = finddiff(dataBp, offsetData, a0, rowpixels, pixel(dataBp, offsetData, a0));
        b1 = finddiff(refline, 0, a0, rowpixels, pixel(dataBp, offsetData, a0) ^ 1);
        b1 = finddiff(refline, 0, b1, rowpixels, pixel(dataBp, offsetData, a0));
    }
}

private void handleHorizontalMode(int a0, int a1, int a2) {
    putcode(horizcode);
    if (a0 + a1 == 0 || pixel(dataBp, offsetData, a0) == 0) {
        putspan(a1 - a0, TIFFFaxWhiteCodes);
        putspan(a2 - a1, TIFFFaxBlackCodes);
    } else {
        putspan(a1 - a0, TIFFFaxBlackCodes);
        putspan(a2 - a1, TIFFFaxWhiteCodes);
    }
}

이 코드의 수정 이유는 주로 가독성을 향상시키고 유지보수를 더 쉽게 하기 위함입니다. 기존 코드는 복잡한 중첩된 if-else 구조로 인해 코드의 흐름을 이해하기 어려웠으며, 메소드의 길이도 너무 길었습니다. 이를 개선하기 위해 수정된 코드에서는 메인 메소드인 Fax3Encode2DRow()를 읽기 쉽게 재구성하고, 각 기능을 별도의 메소드로 만들었습니다.

  1. 메소드 분리: 기존 코드에서는 모든 로직이 한 메소드 안에 중첩되어 있었습니다. 이를 수정하여 각 기능을 별도의 메소드로 분리하였습니다. handleHorizontalMode() 메소드는 가로 모드 처리를 담당하며, 이를 통해 코드의 재사용성과 가독성이 향상되었습니다.
  2. 가독성 향상: 수정된 코드에서는 메소드명을 통해 각 기능의 의도를 명확하게 표현하였습니다. 이로 인해 코드를 읽는 사람이 코드의 동작을 쉽게 이해할 수 있습니다.
  3. 중복 제거: 수정된 코드에서는 중복 코드를 제거하고, 불필요한 if-else 문을 단순화하여 가독성을 높였습니다.

이와 같은 변경으로 인해 코드의 가독성이 향상되었고, 유지보수가 더 쉬워졌습니다.

느낀점

기여 활동을 하기 전에는 이런 일은 대단한 사람들만 할 수 있는 것이라고 생각했습니다. 그러나 실제로 코드에 적용하고 검증받아보니, 자신감이 크게 상승했습니다. 앞으로는 이러한 경험을 통해 버그 수정이나 새로운 기능 추가와 같은 활동을 더 많이 해보고 싶습니다.

Comments