Pular para conteúdo

Comece aqui

O EdgePy Viewer foi organizado em pacotes com responsabilidades distintas. A aplicação reúne esses pacotes e conecta a interface, os dados clínicos e o renderizador por contratos TypeScript. Para acrescentar uma ferramenta, começamos pelo ponto de extensão que atende à sua necessidade.

Na trilha Criando seu componente, vamos conhecer a arquitetura, escolher uma extensão e colocá-la em funcionamento:

Etapa O que você vai aprender
Comece aqui Como o viewer funciona, o papel dos pacotes e onde uma extensão entra
Tipos de componente Escolher entre painéis, renderizadores, resolvedores de assets e outras extensões
Meu primeiro componente Criar e experimentar um painel com uma mensagem e um botão
Histograma Evoluir para uma ferramenta que lê pixels, seleciona uma região e calcula uma distribuição
Utilizando agentes de código Instalar a skill do EdgePy e usá-la no OpenCode para criar uma extensão

Conheça o viewer

O EdgePy Viewer combina a imagem principal com navegação de estudos, seleção de séries, controle de camadas e ferramentas adicionais. A imagem abaixo mostra a aplicação clínica. Nos exercícios, você poderá experimentar esses mesmos componentes em um laboratório com dados sintéticos.

EdgePy Viewer com a área principal de imagem e painéis recolhidos.

Você pode abrir a aplicação atual ou seguir direto para o primeiro exemplo interativo.

Arquitetura limpa: regras separadas das tecnologias

Arquitetura limpa (Clean Architecture) é a organização que mantém as regras da aplicação independentes dos detalhes de interface, armazenamento e bibliotecas externas. A regra de dependência aponta para as partes mais estáveis: o modelo clínico não precisa importar a tecnologia usada para desenhá-lo.

Mapa conceitual com aplicação e adaptadores ao redor dos contratos e do core. As dependências apontam para o centro.

No EdgePy, essa ideia aparece em três decisões:

  • Separar responsabilidades: o modelo clínico fica em core. Leitura DICOM, interface, renderização e execução Python têm pacotes próprios.
  • Programar por contratos: a interface usa uma porta de renderização, implementada pelo Cornerstone. A aplicação pode conectar outro renderer que atenda ao mesmo contrato.
  • Compor na borda: App.tsx escolhe as implementações e registra ferramentas. O pacote de interface oferece pontos de extensão em vez de conhecer cada painel possível.

O mapa é conceitual: nem todos os contratos ficam no core. As portas de viewport vivem em react-viewer, porque descrevem a integração com a apresentação. A regra preservada é que core não dependa da UI, do browser ou dos runtimes externos. O fluxo de dados pode ir e voltar pelos callbacks, sem inverter essa dependência de código.

Como o EdgePy Viewer funciona

Pense no viewer como três partes conectadas pela aplicação:

  1. Modelo clínico: representa estudos, aquisições, séries e camadas sobrepostas. Descreve o que está sendo visualizado.
  2. Interface: apresenta navegação, controles e painéis. Mantém a seleção do usuário e comunica o contexto ativo.
  3. Renderizador: apresenta as imagens no viewport, a área principal de visualização. A implementação atual utiliza Cornerstone.

Em apps/viewer-demo/src/App.tsx, a aplicação recebe os dados preparados pela importação e os entrega ao componente PycomClinicalViewerNext. Também fornece o renderizador e o resolvedor de assets, responsável por obter os arquivos de cada série ou camada.

Arquivos locais ou assets fornecidos pelo host
                    ↓
           Importação na aplicação
                    ↓
App.tsx reúne estudo + resolvedor de assets + renderizador
                    ↓
         PycomClinicalViewerNext
           ├── Navegação e controles
           ├── Viewport → renderizador Cornerstone
           └── customPanels → seus componentes React

Ao mudar a série ou o corte, o viewer atualiza seu contexto. Uma extensão pode receber esse contexto por callback e, quando necessário, solicitar os pixels ao renderizador. Um painel simples pode funcionar apenas com seu próprio conteúdo e estado React.

Conheça os pacotes

O repositório usa workspaces npm: vários pacotes e aplicações são desenvolvidos juntos, com dependências declaradas entre eles. Os nomes históricos pycom permanecem nos imports, como @pycom-next/core e @pycom-next/react-viewer.

Modelo, interface e imagens

Pacote Responsabilidade Exemplo de uso
packages/core Modelo clínico, casos de uso e tipos do contexto do viewer Representar estudos e séries e descrever o snapshot da seleção atual
packages/react-viewer Componentes React, navegação, painéis e contratos do viewport Registrar um painel em customPanels
packages/dicom Portas e adaptadores de leitura DICOM Ler informações dos arquivos para organizar as séries
packages/renderer-cornerstone Implementação do renderizador usando Cornerstone Exibir o corte e fornecer uma cópia de seus pixels
packages/design-system Tokens visuais compartilhados, como cores e raios de borda Manter a identidade visual da interface

Integrações e execução

Pacote Responsabilidade Exemplo de uso
packages/host-integration Contratos e utilitários de integração com o sistema hospedeiro Receber manifestos de assets e pacotes de estudo do host
packages/worker-runtime Comunicação com Web Workers, incluindo requisições, progresso e erros Executar tarefas fora da thread da interface
packages/pyodide-agents Integração dos agentes Python executados no navegador Oferecer ferramentas de processamento pelo editor PyScript

Aplicações que usam esses pacotes

Diretório Papel
apps/viewer-demo Aplicação Vite/React que conecta importação, viewer, renderizador e agentes. É onde faremos os exercícios.
apps/docs-site Documentação que acompanha o repositório público. O laboratório desta trilha é distribuído por este site.

A regra central é manter core independente de React, DOM, Cornerstone e Pyodide. Assim, as regras e os tipos clínicos não precisam conhecer os detalhes da interface ou da biblioteca de renderização.

Como essa separação permite extensões

Um contrato descreve o que uma parte oferece. Um adaptador implementa esse contrato com uma tecnologia concreta. A composição conecta essas partes na aplicação.

Por exemplo, ClinicalViewportRenderer é o contrato de renderização. O adaptador Cornerstone o implementa, e App.tsx entrega a implementação ao viewer pela propriedade viewportRenderer. O painel de histograma, por sua vez, solicita pixels pela interface pública, sem acessar objetos internos do Cornerstone.

Para criar um painel, usamos um contrato ainda menor: ViewerCustomPanel. Ele descreve a chave do painel, seu rótulo e o conteúdo React que será apresentado. A propriedade customPanels recebe essa lista. A partir dela, o viewer cria as ações de abertura e mostra o painel selecionado.

Necessidade da extensão Ponto de integração
Acrescentar um painel React customPanels e ViewerCustomPanel
Usar outro renderizador viewportRenderer e ClinicalViewportRenderer
Resolver assets de outra fonte assetResolver e ClinicalViewportAssetResolver
Acrescentar ações em áreas existentes toolbarActions, railActions, studyPanelActions e inspectorPanelActions
Acompanhar estudo, série e corte ativos onControlPlaneSnapshotChange
Receber as operações disponíveis do renderizador onViewportRendererHandleChange
Obter os pixels do corte, quando o renderizador oferecer essa operação handle.getCurrentImageData()

O snapshot descreve o contexto atual. O handle dá acesso às operações do renderizador ativo. Vamos usar os dois no histograma. Por enquanto, o primeiro componente precisa apenas de customPanels.

A extensão é importada no código da aplicação e incluída no build. Você pode começar uma ferramenta em apps/viewer-demo/src/ e, se precisar reutilizá-la em outras aplicações, movê-la para um pacote próprio.

Prepare o ambiente

Você precisará de Git, npm e Node.js compatível com Vite 7, por exemplo Node 22.12 ou superior da linha 22. Para os exercícios, basta conhecer funções, imports e componentes React básicos.

Os exercícios usam o repositório público do EdgePy Viewer. Clone o projeto e use a revisão abaixo para acompanhar os mesmos contratos apresentados na trilha:

git clone https://github.com/guilhermeRey/ipen-edgepy-viewer.git
cd ipen-edgepy-viewer
git checkout v0.3.0
npm ci
npm run dev

A versão v0.3.0 contém a aplicação, o registro de painéis, a leitura de pixels e a seleção de ROI na imagem principal por beginRectangularRoi(). Abra o endereço mostrado pelo Vite e confira que a interface aparece. O primeiro componente funciona sem importar imagens.

De onde vem cada arquivo?

Todos os caminhos da trilha partem da pasta ipen-edgepy-viewer/ que você acabou de clonar.

Arquivos Como obter
apps/viewer-demo/src/App.tsx e packages/ Já estão no repositório público
HelloPanel.tsx, a pasta histogram/ e syntheticRenderer.ts Crie com o código das páginas ou use o ZIP de exemplos
Suporte à ROI nos pacotes do viewer e do Cornerstone Já está incluído na tag v0.3.0
Skill edgepy-component Baixe na etapa Utilizando agentes de código

Baixar os exemplos para o repositório público

Extraia o ZIP na raiz de ipen-edgepy-viewer/, preservando a estrutura apps/viewer-demo/src/. Ele fornece os arquivos novos. O registro em App.tsx continua sendo feito nos passos do tutorial, para preservar os painéis da sua aplicação.

Os exemplos usam os contratos já publicados na v0.3.0. As alterações do exercício ficam nos componentes da aplicação e no registro em App.tsx.

Os fontes completos do laboratório e seu manifesto de hashes também estão disponíveis para consulta. Você não precisa instalar ou compilar o site de documentação para fazer os exercícios.

O percurso de reprodução usa a tag v0.3.0, os exemplos e o registro dos painéis em App.tsx. As verificações incluem tipagem, testes numéricos, build e seleção na imagem principal. Os arquivos distribuídos têm seus hashes publicados para conferir a versão utilizada.

O que observar sobre extensibilidade

A organização dos pacotes explica onde uma mudança deve entrar. Os exercícios permitem conferir como essa mudança se integra ao viewer:

Pergunta O que observar
Onde foi necessário editar? No primeiro exemplo, um componente novo e o registro em App.tsx
Qual contrato foi utilizado? ViewerCustomPanel, recebido por customPanels
A extensão depende de detalhes internos? Confira seus imports e se foi necessário editar os pacotes do viewer
O comportamento esperado foi obtido? Abra o painel e interaja com o componente
Outra pessoa consegue repetir? Registre a revisão usada, o tempo e as dúvidas durante a reprodução

Essas observações ajudam a avaliar a extensibilidade para a tarefa proposta. A arquitetura indica onde conectar a ferramenta. Ao repetir o exercício, você verifica se os contratos atendem à necessidade e quanto esforço a integração exige.

Onde conferir no código

Na versão pública usada nesta trilha:

  • apps/viewer-demo/src/App.tsx: composição da aplicação e registro dos painéis.
  • packages/react-viewer/src/index.tsx: propriedades públicas e callbacks do viewer.
  • packages/react-viewer/src/components/ViewerDrawers.tsx: contrato e apresentação dos painéis personalizados.
  • packages/react-viewer/src/ports/viewportRenderer.ts: contratos do renderizador e dos pixels.
  • packages/core/src/index.ts: modelo clínico e snapshot.

Próximo passo: conheça os tipos de componente.