2010-05-06 6 views
1

Java/Swing Cobra HTML renderer의 내용을 화면의 BufferedImage로 렌더링하려고합니다. :Java/Swing 오프 스크린 렌더링 (Cobra HTMLPanel -> BufferedImage) 문제 : 구성 요소가 먼저 다시 그려지지 않습니다.

slideViewPanel.setDocument(document, rendererContext); 
BufferedImage test = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB); 
Graphics g = test.getGraphics(); 
slideViewPanel.paint(g); 

결과 이미지 g는 부분적으로 렌더링 된 페이지를 보여줍니다. 새 문서가 설정되기 전에 HTMLFrame의 내용이 표시되는 경우도 있습니다. 때로는 새 문서의 절반 렌더링 된 버전입니다. Cobra의 setDocument 메소드가 문서를 다시 렌더링하도록 예약했기 때문에 이것이 수집되었지만 디버거에서 단계별로 진행 중이며 렌더링을 다시 수행 할 두 번째 스레드가 표시되지 않습니다. 누구나 여기서 무슨 일이 일어날 지 알 수 있습니까?

답변

1

, 당신은 모든 이미지 구성 요소를 배치하기 전에로드 될 때까지 기다릴 필요가있다.

구성 요소를 레이아웃하기 전에 모든 이미지가 완전히로드되었는지 확인하기 위해 모든 이미지로드를 차단하십시오. HtmlDocumentImpl.loadImage를 오버라이드하여이 작업을 수행했습니다. (DocumentBuilderImpl을 서브 클래스 화하고 createDocument를 오버라이드하여 작동되게해야했습니다.) image.getWItdh의 결과가 나올 때까지 기다리는 세마포어를 사용했습니다.

일부 스크립트가 반복되어 돌아 오지 않을 수 있으므로 구문 분석과 관련하여 타이머를 설정해야했습니다. 이 문제를 해결하는 더 좋은 방법이 있는지 나는 모른다.

레이아웃에 관해서는 아래에서 잘라내기로 이어지는화물 숭배와 실험 거래가 있습니다. 따라서 일부를 제거하려고 시도 할 수 있습니다.

  htmlPanel.setVisible(true); 
    htmlPanel.setPreferredWidth(DEFAULT_PAGE_WIDTH); 
    logger.info("Calculating preferred size"); 

    // Get the preferred heigth for the current width. 
    Dimension psvz = htmlPanel.getPreferredSize(); 
    Dimension min = htmlPanel.getMinimumSize(); 

    logger.info("prf :" + psvz); 
    logger.info("min :" + min); 

    // Enlarge to the minimum width (with a limit) 
    int width = Math.min(MAX_PAGE_WIDTH, Math.max(DEFAULT_PAGE_WIDTH, 
      psvz.width)); 
    int height = psvz.height; 

    logger.info("width :" + width); 
    logger.info("heigth :" + height); 

    htmlPanel.setSize(width, height); 

      // actually, htmlPanel is a subclass, and this method exposes validateTree. It may work without it. 
    htmlPanel.forceValidateTree(); 

    htmlPanel.doLayout(); 

    setImageSize(width); 
    logger.info("actual size:" + htmlPanel.getSize()); 

JFrame이 HtmlPanel에서 수행하는 작업을 알아낼 수 없어서 아이를 제대로 칠하도록했습니다. children 컴포넌트를 사용하여 페인트해야했습니다. 즉, htmlPanel.getBlockRenderable() 또는 프레임 셋 중 하나입니다.

이미지는 비 윤곽 페인트되어 페인트가 중단 될 수 있으므로 BufferedImage를 사용하려면 먼저 모든 이미지 페인트를 완료해야합니다.

그림이 완료 될 때까지 기다리는 모든 이미지 페인트 메서드를 재정의하는 위임 된 graphics2d 개체가 사용되었습니다.

그 후, 나는 html이 모든 이미지 크기가 알려진대로 재 레이아웃의 이점을 얻을 수 있다는 것을 알아 냈습니다. 그래서 구성 요소를 무효화하고 레이아웃 및 페인팅을 다시 수행합니다 (또는 실제로, 저는 두 번 코드를 호출합니다 ...). .)

그런 다음 BufferedImage를 사용할 수 있습니다. 어쩌면 더 간단한 방법이있을 것입니다.

0

시도 구성 요소가 이미지를 얻을 보일 때까지 기다려야 g.dispose()

+0

g과 같은 'SwingUtilities.invokeAndWait()'가 있습니다.dispose()는 불완전한 렌더링에는 도움이되지 않지만 지적 해 주셔서 감사합니다. API를 사용하면 그래픽 컨텍스트에서 사용해야하는 것과 같은 사운드가 들립니다. Cobra docs를 보면 "setDocument"호출이 페이지를 렌더링하기보다는 그 자리에서 렌더링하는 것처럼 보입니다. 그래도 "렌더링 완료"에 해당하는 함수/이벤트 알리미가있는 것 같지 않습니다. – Alterscape

+0

그러면 소스 코드를 얻고 그걸 파헤쳐 야합니다. – Guillaume

0

당신은해야합니다 호출. 그와 함께 시도 :

htmlPanel.setDocument(document, rendererContext); 
    EventQueue.invokeLater(new Runnable() { 
    public void run() { 
    if (!captureImage(htmlPanel, "test.jpg")){ 
    EventQueue.invokeLater(this); 
    System.out.println("Encolado"); 
    }else { 
    System.out.println("capturado"); 
    } 
    } 
    }); 

을로 captureImage을 갖는 페이지를 구문 분석 된 경우

public static boolean captureImage(Component component, String fileName) { 
    boolean captured = false; 
    if (component.isVisible()) { 
    Dimension size = component.getSize(); 
    BufferedImage image = new BufferedImage(size.width, size.height, 
    BufferedImage.TYPE_INT_RGB); 

    component.paint(image.getGraphics()); 
    captured = true; 
    try { 
    ImageIO.write(image, "JPEG", new File(fileName)); 
    } catch (IOException e) { 
    e.printStackTrace(); 
    } 
    } 
    return captured; 
} 
0

사실, 'component.paint (image.getGraphics());'를 둘러 쌉니다.

try { 
    SwingUtilities.invokeAndWait(new Runnable() { 
     public void run() { 
      component.paint(image.getGraphics()); 
     } 
    }); 
    ImageIO.write(image, "png", file); 
} catch (Exception e) { 
    } finally { 
    }