Wednesday 14 February 2018

0xf0 binary options


Este documento apresenta o cuobjdump. Nvdisasm. E nvprune. Três ferramentas binárias CUDA para Linux (x86 e ARM), Windows, Mac OS e Android. Um arquivo CUDA binário (também conhecido como cubin) é um arquivo formatado em ELF que consiste de seções de código executável CUDA, bem como outras seções contendo símbolos, relocators, informações de depuração, etc. Por padrão, o driver de compilador CUDA nvcc incorpora arquivos de cubo No arquivo executável do host. Mas eles também podem ser gerados separadamente usando a opção - cubin do nvcc. Os arquivos de cubin são carregados em tempo de execução pela API de driver CUDA. Nota: Para obter mais detalhes sobre os arquivos do cubin ou a trajetória de compilação do CUDA, consulte NVIDIA CUDA Compiler Driver NVCC. CUDA fornece dois utilitários binários para examinar e desmontar arquivos de cubo e executáveis ​​de host: cuobjdump e nvdisasm. Basicamente, cuobjdump aceita arquivos de cubo e binários de host enquanto nvdisasm só aceita arquivos de cubo, mas nvdisasm fornece opções de saída mais ricas. Tabela 1. Comparação de cuobjdump e nvdisasm cuobjdump extrai informações de arquivos binários CUDA (tanto autônomos quanto incorporados em binários de host) e os apresenta em formato legível para humanos. A saída de cuobjdump inclui CUDA assembly código para cada kernel, CUDA ELF seção cabeçalhos, seqüência de caracteres tabelas, relocators e outras CUDA seções específicas. Ele também extrai o texto ptx embutido de binários de host. Para obter uma lista do conjunto de instruções de montagem CUDA de cada arquitetura de GPU, consulte Referência de conjunto de instruções. Cuobjdump aceita um único arquivo de entrada cada vez que é executado. A utilização básica é a seguinte: Para desmontar um cubo ou cubos autônomos incorporados em um executável do host e mostrar o assembly CUDA dos kernels, use o seguinte comando: Para despejar seções de cuda elf em formato legível de um arquivo cubin, use o seguinte comando : Para extrair texto ptx de um binário de host, use o seguinte comando: Heres uma saída de amostra de cuobjdump. Conforme mostrado na saída, o binário do host a. out contém código de cubin e ptx para sm20. Para listar os arquivos do cubin no uso binário do host - lelf opção: Para extrair todos os cubins como arquivos do host binário use - xelf all option: Para extrair o cubin chamado addnew. sm30.cubin. Para extrair apenas os cubins contendo old em seus nomes: Você pode passar qualquer substring para - xelf e - xptx opções. Somente os arquivos com a substring no nome serão extraídos do binário de entrada. Para despejar informações de uso de recursos comuns e por função: Observe que o valor para REG, TEXTURE, SURFACE e SAMPLER denota a contagem e para outros recursos denota não. De byte (s) utilizado (s). A Tabela 2 contém as opções de linha de comando suportadas de cuobjdump. Juntamente com uma descrição do que cada opção faz. Cada opção tem um nome longo e um nome curto, que pode ser usado de forma intercambiável. Tabela 2. Opções de Linha de Comando cuobjdump --extract-elf ltpartial file namegt. Extraia o nome dos arquivos ELF contendo o nome do arquivo ltpartial e salve como arquivo (s). Use tudo para extrair todos os arquivos. Para obter a lista de arquivos ELF use a opção - lelf. Funciona com host executável / objeto / biblioteca e fatbin externo. Todas as opções de dump e lista são ignoradas com esta opção. --extract-ptx nome do arquivo ltpartial. Extraia o nome dos arquivos PTX contendo o nome do arquivo ltpartial e salve como arquivo (s). Use tudo para extrair todos os arquivos. Para obter a lista de arquivos PTX, use a opção - lptx. Funciona com host executável / objeto / biblioteca e fatbin externo. Todas as opções de dump e lista são ignoradas com esta opção. --função de função ltf. Especifique os nomes das funções do dispositivo cujas estruturas binárias de gordura devem ser despejadas. --function-index ltfunction indexgt. Especifique o índice da tabela de símbolos da função cujas estruturas binárias de gordura devem ser despejadas. --gpu-architecture ltgpu architecture namegt Especifica a arquitetura da GPU para a qual as informações devem ser despejadas. Valores permitidos para esta opção: sm20, sm21, sm30, sm32, sm35, sm37, sm50, sm52, sm53, sm60, sm61. Imprima esta informação de ajuda nesta ferramenta. Liste todos os arquivos ELF disponíveis no fatbin. Funciona com host executável / objeto / biblioteca e fatbin externo. Todas as outras opções são ignoradas com este sinalizador. Isso pode ser usado para selecionar ELF particular com a opção - xelf mais tarde. Liste todos os arquivos PTX disponíveis no fatbin. Funciona com host executável / objeto / biblioteca e fatbin externo. Todas as outras opções são ignoradas com este sinalizador. Isso pode ser usado para selecionar PTX específico com a opção - xptx mais tarde. Inclua opções de linha de comando do arquivo especificado. Nvdisasm extrai informações de arquivos de cubo autônomos e os apresenta em formato legível. A saída de nvdisasm inclui CUDA assembly código para cada kernel, lista de ELF dados seções e outras CUDA seções específicas. Estilo de saída e opções são controladas através de opções de linha de comando nvdisasm. O nvdisasm também controla a análise de fluxo para anotar alvos de salto / ramo e torna a saída mais fácil de ler. Observação: o nvdisasm requer informações de realocação completas para fazer análise de fluxo de controle. Se esta informação estiver ausente do binário CUDA, use a opção nvdisasm - ndf para desativar a análise de fluxo de controle ou use a opção ptxas e nvlink - preserve-relocs para re-gerar o arquivo cubin. Para obter uma lista do conjunto de instruções de montagem CUDA de cada arquitetura de GPU, consulte Referência de conjunto de instruções. Nvdisasm aceita um único arquivo de entrada cada vez que é executado. O uso básico é o seguinte: Para obter o gráfico de fluxo de controle de um kernel, use o seguinte: Heres uma saída de amostra de nvdisasm. O nvdisasm é capaz de gerar o fluxo de controle do assembly CUDA no formato da linguagem de descrição do gráfico DOT. A saída do fluxo de controle de nvdisasm pode ser importada diretamente para uma ferramenta de visualização de gráfico DOT, como Graphviz. Nota: Este recurso é suportado somente em cubins gerados para Compute Capability 3.0 e posterior. Heres como você pode gerar uma imagem PNG (cfg. png) do fluxo de controle do cubo acima (a. cubin) com nvdisasm e Graphviz: Heres o gráfico gerado: Figura 1. Gráfico de fluxo de controle nvdisasm é capaz de mostrar o registro ( CC, geral e predicado). Para cada linha de montagem CUDA, nvdisasm exibe se um determinado registro de dispositivo foi atribuído, acessado, ao vivo ou reatribuído. Mostra também o número total de registos utilizados. Isso é útil se o usuário estiver interessado no intervalo de vida de qualquer registro particular, ou registrar o uso em geral. Nota: Este recurso é suportado somente em cubins gerados para Compute Capability 3.0 e posterior. Heres uma saída de amostra (colunas esquerdas são omitidas): Tabela 3 contém as opções de linha de comando suportadas de nvdisasm. Juntamente com uma descrição do que cada opção faz. Cada opção tem um nome longo e um nome curto, que pode ser usado de forma intercambiável. Tabela 3. Opções de linha de comando do nvdisasm nvprune aceita um único arquivo de entrada cada vez que ele é executado, emitindo um novo arquivo de saída. O uso básico é o seguinte: O arquivo de entrada deve ser um objeto de host relocável ou uma biblioteca estática (não um executável de host) eo arquivo de saída terá o mesmo formato. A opção --arch ou --generate-code deve ser usada para especificar o (s) alvo (s) a ser mantido. Todo o outro código de dispositivo é descartado do arquivo. Os alvos podem ser um arco smNN (cubin) ou um arco computeNN (ptx). Por exemplo, o seguinte irá prune libcublasstatic. a para conter apenas sm35 cubin em vez de todos os alvos que normalmente existem: Note que isso significa que libcublasstatic35.a não será executado em qualquer outra arquitetura, por isso só deve ser usado quando você está construindo para Uma única arquitetura. A Tabela 7 contém as opções de linha de comando suportadas do nvprune. Juntamente com uma descrição do que cada opção faz. Cada opção tem um nome longo e um nome curto, que pode ser usado de forma intercambiável. Tabela 7. Opções da linha de comando nvprune TODAS AS ESPECIFICAÇÕES, PLACAS DE REFERÊNCIA, ARQUIVOS, DESENHOS, DIAGNÓSTICOS, LISTAS E OUTROS DOCUMENTOS DA NVIDIA DESIGN (JUNTO E SEPARADAMENTE, MATERIAIS) ESTÃO FORNECIDOS COMO ESTÃO. A NVIDIA NÃO OFERECE GARANTIAS, EXPRESSAS, IMPLÍCITAS, ESTATUTÁRIAS OU DE OUTRA FORMA COM RELAÇÃO AOS MATERIAIS E EXPRESSAMENTE SE ISENTA DE TODAS AS GARANTIAS IMPLÍCITAS DE NÃO INFRAÇÃO, COMERCIABILIDADE E ADEQUAÇÃO A UM DETERMINADO PROPÓSITO. A informação fornecida é acreditada para ser exata e de confiança. No entanto, a NVIDIA Corporation não assume qualquer responsabilidade pelas consequências da utilização de tais informações ou por qualquer violação de patentes ou outros direitos de terceiros que possam resultar da sua utilização. Nenhuma licença é concedida por implicação de outra forma sob quaisquer direitos de patente da NVIDIA Corporation. As especificações mencionadas nesta publicação estão sujeitas a alterações sem aviso prévio. Esta publicação substitui e substitui todas as outras informações anteriormente fornecidas. Os produtos NVIDIA Corporation não são autorizados como componentes críticos em dispositivos ou sistemas de suporte de vida sem a aprovação expressa e por escrito da NVIDIA Corporation. Marcas Registradas NVIDIA eo logotipo NVIDIA são marcas comerciais ou marcas registradas da NVIDIA Corporation nos Estados Unidos e em outros países. Outros nomes de empresas e produtos podem ser marcas registradas das respectivas empresas com as quais estão associados. Binário de módulo Ao lidar com soquetes de rede ou arquivos binários, é necessário ler e gravar em fluxos de bytes. O JavaScript propriamente dito não fornece uma representação nativa de dados binários, portanto, este módulo fornece duas classes que abordam essa lacuna. A implementação segue a proposta CommonJS Binary / B. ByteArray implementa um buffer de bytes modificável e redimensionável. ByteString implementa uma seqüência de bytes imutável. Ambas as classes compartilham uma classe base comum binária. A classe base não pode ser instanciada. Ele existe apenas para afirmar que ByteString e ByteArray instâncias de binário. Quando passado para um método Java que espera um byte. Instâncias dessas classes são automaticamente desempacotadas. Classe Classe binária ByteArray Métodos de instância Propriedades de instância Métodos estáticos Classe ByteString Métodos de instância Propriedades de instância Métodos estáticos Classe String Instância métodos Classe de base abstrata para ByteArray e ByteString. O tipo binário existe apenas para afirmar que ByteString e ByteArray instâncias de binário. ByteArray (contentOrLength, charset) Constrói uma matriz de bytes gravável e expansível. Se o primeiro argumento para esse construtor for um número, ele especifica o comprimento inicial do ByteArray em bytes. Else, o argumento define o conteúdo do ByteArray. Se o argumento for uma String, o construtor requer um segundo argumento contendo o nome da codificação Strings. Se chamado sem argumentos, um ByteArray vazio é retornado. ParametersExploring JPEG Este arquivo é um arquivo HTML e um programa Haskell alfabetizado. Se você renomeá-lo para. lhs você pode compilá-lo com GHC 6.6. Este é um decodificador JPEG funcional, se limitado. Ele só decodifica tons de cinza, imagens de 8 bits e é excessivamente sensível às opções usadas. Eu pensei que as pessoas podem gostar de aprender um pouco sobre o padrão JPEG. Francamente, você pode simplesmente ignorar todo o código se você não entende Haskell. Um bitstream JPEG consiste em vários segmentos. Cada byte no arquivo pertence a um segmento e cada segmento segue um formato comum: 0x01. 0xfe (tipo de segmento) comprimento do cabeçalho (frequentemente incluído, mas não sempre) Após o cabeçalho bytes de comprimento pode vir um fluxo codificado de bytes. Se o fluxo codificado de bytes contiver um 0xff. Um 0 x 00 é recheado depois para se certificar de que o 0xff isnt confundido com o início do próximo cabeçalho. Eu vou colocar no primeiro pedaço de código agora, então eu tenho que tirar o módulo de coisas fora do caminho. Você pode ignorar este são todos os módulos padrão, exceto para BitSyntax que é um módulo auxiliar para análise de formatos binários. Agora, heres o código que leva um arquivo JPEG e retorna uma lista de segmentos. Ele procura o marcador de início de segmento e retorna uma lista de tipos de segmento eo corpo desse segmento. Seu um pouco frouxo porque não pula o cabeçalho do segmento para aqueles segmentos que têm um comprimento. Assim é possível que ele vai encontrar um marcador nos cabeçalhos. No entanto, basta para as nossas necessidades. Neste ponto Ill apresentar nossa imagem de teste: Executando jpegSegments neste arquivo dá os seguintes segmentos Tipo de segmento Comprimento do segmento O segmento APP0 marca este arquivo como um JFIF / JPEG. JFIF define alguns campos extras (como a resolução da imagem e uma miniatura opcional) e você pode descobrir mais sobre isso aqui. Quase todos os JPEGs encontrados na natureza serão arquivos JFIF. O esboço do arquivo JPEG é que ele contém um quadro (imagem) e que o quadro pode uma das varreduras mais. As varreduras podem dar progressivamente mais detalhes, ou podem ser eixos diferentes do espaço de cores etc. Para este exemplo, temos apenas uma varredura e apenas um eixo de espaço de cor (luminância, por causa de sua escala de cinza). As tabelas de quantificação e Huffman são necessárias para a descodificação da imagem, então a primeira coisa que fazemos é analisar e armazenar as informações neles. Bem estar armazenando as informações em uma estrutura: Pode haver muitas tabelas Huffman e quantisation definidas e varreduras diferentes podem usar tabelas diferentes. Então, nós armazenamos um mapa de tabelas, embora só esperamos um. Primeiro analisamos a tabela de quantificação (o segmento é chamado DQT na especificação JPEG e você verá esses nomes de tripleto aparecendo de vez em quando). Não se preocupe com o que uma tabela de quantificação é ainda muito, bem chegar a isso mais tarde, é basicamente apenas uma matriz de valores de 64. O segmento de tabela de quantificação se parece com: 0xdb (tipo de segmento) comprimento de precisão de segmento em 64 elementos de u8 ou U16 valores de quantificação em ordem ziguezague As últimas três linhas são repetidas para o comprimento do segmento. Heres o código de análise Huffman codificação Im indo para assumir que você sabe o que Huffman codificação é, se não você pode ler sobre ele. JPEG define um modo para Huffman e codificação aritmética, mas, devido a questões de patentes, apenas Huffman é visto na natureza. A codificação aritmética é mais lenta, mas obtém cerca de 10 compressão melhor para arquivos JPEG. As árvores de Huffman em JPEG nunca são mais profundas do que 16 elementos e são comunicadas com duas listas. O primeiro é 16 elementos de comprimento e dá o número de valores em cada profundidade na árvore. (Assim, o primeiro elemento dá o número de valores que são apenas um passo da raiz da árvore, o segundo o número que são dois passos, etc). A segunda lista é uma lista de elementos, por ordem de profundidade. O padrão JPEG fornece uma definição muito complexa de como construir as árvores de Huffman (o que parece ser um caso de otimização prematura). O algoritmo real é o seguinte: Comece com uma árvore vazia Para cada par (elemento, profundidade) na lista de elementos (em ordem): Vá passos em profundidade a partir da raiz, sempre indo para a esquerda em cada etapa se há espaço para fazê-lo. (Os elementos estão sempre nas folhas das árvores, então se a subárvore esquerda é um elemento, ou é uma árvore completamente terminada por elementos, você não pode ir para a esquerda) Onde você parar, insira o elemento Heres nossa estrutura de árvore: Cada nó no Árvore está vazia. Full (um nó folha, com no elemento Int) ou uma árvore com uma fullness-flag, e leftright filhos. O sinalizador de plenitude para cada nó de árvore é verdadeiro se não mais elementos podem ser inseridos nele. Isso nos poupa da necessidade de retroceder. O tipo Branch é usado para armazenar os passos que levamos para inserir o elemento. Isso é necessário se você está indo para implementar uma pesquisa de tabela rápida (não estamos neste caso, por isso é apenas um exemplo.) Heres a função para adicionar um elemento para a árvore. Você pode verificar os padrões, se quiser: Construir uma árvore é apenas um caso de chamar huffTreeAdd para cada par (profundidade, elemento) na tabela Huffman. Nós jogamos fora o caminho de Branch es, mas isso é onde você iria construir uma tabela de pesquisa se você queria velocidade. Olhando acima valores da árvore é muito simples, você apenas anda a árvore até que você bate um elemento. Esta função usa uma lista de Bool s como uma lista de bits onde true significa tomar a subárvore direita. Retorna o elemento e a lista restante de bits. Agora que você conhece a teoria, há apenas a questão de como ler os bytes. Lembre-se que só precisamos da lista de comprimentos e da lista de elementos, a partir da qual o layout do segmento é óbvio: elementos, por ordem de profundidade Como as tabelas de quantização, as últimas quatro linhas são repetidas para o comprimento do segmento. Heres a função de análise, retorna a classe, id e uma lista de pares (de profundidade, elemento): Existem dois outros segmentos que precisamos analisar, o início da moldura eo início da digitalização. Seus formatos exatos não são importantes, eles contêm o que você esperaria: a largura ea altura da imagem, número de componentes (eixo de espaço de cor) e quais tabelas para usar na decodificação: Theres também uma função que traduz os valores de retorno destas parsing Funções em mudanças na estrutura JpegState (que nós definimos maneira acima se você lembrar): A Transformação de Coseno Discreto estavam quase prontos para começar a decodificar o coração de JPEG - o DCT. Ao codificar uma imagem, sua divisão em 8x8 quadrados de pixels. Cada um desses quadrados é então transformado através da DCT (que é totalmente reversível). Você pode pensar no DCT como alterando os pixels do tempo para o domínio da freqüência: o gráfico tempo vs amplitude de uma forma de onda está no domínio do tempo ea parcela de frequência vs amplitude (como você vê em um equalizador gráfico) está na freqüência domínio. O DCT é totalmente reversível. Você também pode pensar no DCT como uma função que transforma uma grade de 8x8 pixels em uma combinação linear das seguintes funções de base gráfica: Existem 64, 8x8 imagens lá. O superior esquerdo é chamado de componente DC e todo o resto são componentes AC. Esperançosamente você pode ver que um bloco 8x8 contínuo é sempre alguma fração do azulejo esquerdo superior. Se o bloco de 8x8 desvanece-se para o fundo, adicione então um pouco da telha imediatamente abaixo. Pode não ser óbvio que todos os blocos de 8x8 pixels podem ser representados como combinações lineares dessas telhas, mas é verdade. A componente DC é a onda de coseno que não faz ciclos sobre o bloco 8x8. Indo um azulejo à esquerda, essa é a onda de coseno que faz metade de um ciclo sobre o bloco. Próxima telha ao longo faz um ciclo sobre o bloco e assim por diante. Ir para esquerda aumenta a frequência horizontal e descer aumenta a frequência vertical. No entanto, o olho humano tem sensibilidades diferentes nestas frequências. A maioria das telhas de alta freqüência pode ser jogada fora sem qualquer efeito perceptível. Este jogando fora é gerenciado dividindo a amplitude de cada ladrilho por um número fixo na esperança de que muitos deles vão para zero. Quanto maior o divisor, menor a qualidade e os divisores são ponderados de modo que os componentes de alta freqüência são divididos por um número maior. A lista de divisores é a tabela de quantificação que tratamos antes. Você pode executar o DCT correlacionando os valores de pixel com as funções coseno, que, para o caso 1-d, é o mesmo que multiplicar pela matriz DCT: Como cada linha é ortogonal, o inverso dessa matriz é apenas sua transposição. Representamos uma matriz como uma lista de linhas, onde cada linha é uma lista de valores. Isto nos dá as funções de transposição, vetorvector, matrizvector e matrixmatrix: Também podemos definir a matriz DCT 8x8 inversa: codificação DCT Agora entendemos que para decodificar a imagem precisamos apenas obter os coeficientes DCT para cada bloco 8x8, multiplicar pela quantificação Tabela e executar a DCT inversa para obter os valores de pixel. A questão restante é como decodificar os coeficientes DCT. Primeiro, os blocos 8x8 são codificados em ordem de varredura (da esquerda para a direita, de cima para baixo) e, onde a imagem não é um número inteiro de blocos de 8x8, os pixels mais à direita e mais baixos são repetidos para torná-lo assim. Para cada bloco 8x8 o coeficiente DC é codificado primeiro usando uma tabela de Huffman e os coeficientes de AC seguem (todos os 63 deles) usando outra tabela de Huffman (e outro esquema de codificação). Ambos DC e AC usam o mesmo esquema de codificação inteiro, no entanto, que é o que bem cobrir próxima: Um número inteiro é codificado por Huffman codificação seu intervalo e, em seguida, twos complementar a codificação do deslocamento dentro desse intervalo. Os intervalos têm a seguinte aparência: SSSS (número de intervalo) O valor SSSS é o elemento da árvore Huffman (para DC) eo número de bits de arrasto. Portanto, se você decodificar 3 da árvore de Huffman, você toma os três bits a seguir do fluxo de bits. O primeiro desses bits é verdadeiro se você está contando a partir do fundo da subrange positivo e false se você está contando a partir do fundo da subrange negativo. Os dois últimos são o número a ser adicionado a esse valor base: O valor DC de cada bloco DCT é codificado como a diferença do valor DC do último bloco decodificado. (O valor DC do bloco antes do primeiro é considerado 0). Este código não faz a diferença, apenas decodifica o valor: os valores AC são um pouco diferentes. Em primeiro lugar, há 63 deles em cada bloco e geralmente há longas corridas de zeros entre valores. Assim, a árvore AC Huffman decodifica dois valores: um valor SSSS (nos 4 bits inferiores), tal como acima e um valor RRRR (nos quatro bits superiores), que dá o número de zeros anteriores. Portanto, se a árvore AC Huffman decodifica um valor de 0x53, isso é SSSS 3 e RRRR 5 e resulta nos valores 0, 0, 0, 0, 0, x. Onde x está na gama -31 ..- 16,16..31. Você decodificar os três bits a seguir para localizar o valor exato para x. Existem também códigos especiais para 16 zeros (0x00) e para terminar os valores de CA para este bloco (0xf0) uma vez que os blocos terminam frequentemente com muitos valores zero. Claramente, a codificação Huffman dos valores AC funciona melhor quando há lotes de execuções de zeros e muitos zeros no final. Componentes de alta freqüência são susceptíveis de ser quantised a zero, mas se tomarmos os valores de CA em ordem raster, os componentes de freqüência mais alta não estarão sempre no final. Assim, os valores de CA são codificados em ordem ziguezague. Heres um diagrama: E heres o código: Estamos, finalmente, pronto para decodificar o JPEG, mas primeiro eu preciso para obter algumas funções auxiliares fora do caminho. Os dois primeiros (groupSize e d8ru) são triviais. O último, bytesToBits converte um bloco de dados de memória em uma lista de bits, removendo o 0x00 recheado após cada 0xff (lembre-se que esses bytes recheados são colocados lá para parar os dados de Huffman parecendo o início do próximo segmento). Agora, a função de decodificação. Ive adicionou comentários no final de algumas das linhas para que você possa acompanhar. Primeiro vamos descobrir quantos blocos DCT existem (0), este é apenas o número de blocos em uma linha vezes o número de linhas sobre a altura de um bloco. Em seguida, (1) decodificamos o delta DC e adicionamo-lo ao último valor DC (2). Então podemos decodificar todos os valores AC (3) e multiplicar todos os coeficientes DCT pela tabela de quantificação (4). Finalmente des-ziguezague e realizamos a DCT inversa (5) e foram feitas. Isto é feito para cada bloco DCT no arquivo e nós terminamos com uma lista de 8x8 matrizes de valores de pixels. Esses valores de pixel são de -128 a 128 (porque o DCT funciona melhor quando eles são simétricos em torno de 0). Devido a alguns erros de arredondamento, os valores reais podem exceder esse intervalo e, portanto, precisam ser fixados no tempo de saída. Acabamento A última função fornece a lista de matrizes de valores de pixels para um arquivo PGM. Percorremos cada linha de valores de DCT oito vezes para obter cada linha de varredura (0) e, para cada valor de pixel, somamos 128 e prendemos o intervalo (1). E então theres a função principal que apenas faz um decodificador de exemplo que lê de test. jpeg e escreve para out. pgm. Heres o resultado (convertido a um PNG):

No comments:

Post a Comment