[Música tocando] ZAMYLA CHAN: Foi senhorita Scarlett com o castiçal. Whodunit? Bem, vamos descobrir. No Clue jogo de tabuleiro, você pode ser dada uma imagem vermelha física. E essa imagem é muito vermelho e irregular, e seu trabalho é revelar a mensagem escondida. E, geralmente, você está equipado com um vermelho lupa, ou uma tela vermelha para revelam que a mensagem escondida. Bem, nós estamos indo para imitar isso. No romance policial, você está dado uma imagem bitmap que se parece muito irregular e vermelho, e, em seguida, executar o programa whodunit para revelar uma mensagem escondida. Então, vamos quebrar isso em etapas. Em primeiro lugar, você deseja abrir o arquivo - a pista que lhe foi dado. E depois também criar um arquivo veredicto bitmap. Então você deseja atualizar o bitmap cabeçalho informações para o outfile veredicto. Mais sobre isso mais tarde. E então você vai ler na pista, scanline, pixel por pixel, mudando as cores do pixel como necessário, e escrita aqueles em que o veredicto - pixel por pixel na scanline veredicto. Como é que vamos começar a ir a este respeito? Bem, felizmente, temos copy.c no código de distribuição. E isso vai provar muito útil para nós. Copy.c abre um arquivo, lê nesse cabeçalho do infile, e atualiza o cabeçalho do arquivo de saída. E, em seguida, lê-se a cada pixel na scanline, pixel por pixel, e, em seguida, escreve que de pixel para o arquivo de saída. Então, o primeiro passo pode a de executar o seguinte comando no terminal - cp copy.c whodunit.c. Isto irá criar uma cópia de copy.c chamado whodunit.c. Assim, o nosso primeiro passo para abrir o arquivo, bem, há uma exata réplica do que em copy.c. Então, eu vou deixar você olhar para isso. O que estamos lidando neste PSET é arquivo I / O, basicamente tomando arquivos, leitura, escrita, editá-los. Como você abre um arquivo? Bem, você está indo para declarar um arquivo ponteiro, e depois você chamar o função fopen. Passe no caminho, ou o nome da arquivo e, em seguida, o modo que você quer para abrir esse arquivo dentro Passando uma r abrirá foo.bmp para a leitura. Considerando fopen com passando um w vai bar.bmp aberto, para gravar o arquivo e realmente editá-lo. Portanto, agora que você abriu o arquivo, a nossa próximo passo é atualizar as informações do cabeçalho para o arquivo de saída. O que é uma informação de cabeçalho? Bem, primeiro precisamos saber o que é um bitmap é. Um bitmap é apenas um simples arranjo de bytes. E eles estão declarados neste arquivo aqui, bmp.h, com um monte de informação do que um bitmap é realmente feita de fora. Mas o que realmente importa é o cabeçalho do arquivo bitmap, bem aqui, e a informação bitmap cabeçalho, aqui. O cabeçalho é constituído por um par de variáveis ​​que poderá ser muito útil. Há biSizeImage, que é o tamanho total da imagem em bytes. E isso inclui pixels e estofamento. Padding é muito importante, mas nós vamos chegar a isso mais tarde. BiWidth representa a largura da imagem em pixels menos o estofamento. BiHeight é então também a altura da imagem em pixels. E, em seguida, o BITMAPFILEHEADER ea BITMAPINFOHEADER, como mencionei anterior, aqueles representados como estruturas. Então, você não pode acessar o cabeçalho do arquivo si mesmo, mas você vai querer começar a essas variáveis ​​dentro. OK. Então, como vamos atualizar as informações do cabeçalho? Bem, primeiro temos que ver se nós precisa alterar qualquer informação do o infile, a pista, com o outfile, o veredicto. Qualquer coisa está mudando neste caso? Bem, não realmente, porque nós vamos para ser apenas mudando as cores. Nós não vamos estar mudando o arquivo o tamanho, o tamanho da imagem, a largura, ou a altura. Então, você está bem por agora por apenas copiando cada pixel. OK. Então agora vamos olhar como nós, na verdade, pode ler cada pixel do arquivo. Outro arquivo função I / O vai entrar em jogo - fread. Leva em um ponteiro para a struct que irá conter os bytes você está lendo. Então você está lendo para isso. E então você passa em um tamanho, que é o tamanho de cada elemento que lhe deseja ler. Aqui, a função sizeof virá a calhar. Então você passa em número, que representa o número de elementos de tamanho de ler. E, em seguida, finalmente, inptr, que é o ponteiro do arquivo que você está indo para ler. Então, todos esses elementos estão dentro inptr e eles estão indo para dados. Vejamos um pequeno exemplo. Se eu quero ler em dados de dois cães, bem, eu posso fazer isso de duas maneiras. I pode ler em dois objetos de tamanho cão do meu inptr, ou eu posso ler em um objeto do tamanho de dois cães. Então você vê que, dependendo da forma que você organize tamanho e número, você pode ler o mesmo número de bytes. Então, agora, vamos mudar o pixel de cor como nós precisamos. Se você olhar para bmp.h novamente, então você verá que na parte inferior RGBTRIPLEs são outra estrutura, onde eles são constituídos por três bytes. Um, rgbtBlue, rgbtGreen, e rgbtRed. Assim, cada um deles representa a quantidade de azul, a quantidade de verde, eo quantidade de vermelho dentro deste pixel, onde cada valor é representado por um número hexadecimal. Então ff0000 será uma cor azul, porque ele vai de azul, a verde, a vermelha. E então, f será de branco. Vamos dar uma olhada em smiley.bmp, que você tem no seu código de distribuição. Se você abri-lo em apenas uma imagem espectador, então você basta ver um smiley vermelho. Mas tomar um mergulho mais profundo em, vamos ver que a estrutura de que é apenas pixels. Temos pixels brancos, e, em seguida, vermelho pixels. O branco, ffffff, e então todo o pixels vermelhos Eu coloridas em para você aqui, e você vê que eles estão 0000ff. Zero azul, verde zero, e cheio vermelho. E uma vez que emoticon é de oito pixels de largura, não temos qualquer preenchimento. Tudo bem. Então, se eu fosse para atribuir valores diferentes a um RGBTRIPLE e eu queria torná-lo verde, então o que eu gostaria de fazer é Gostaria de declarar um RGBTRIPLE, nomeado triplo, em seguida, para acessar cada byte em que a estrutura I usaria o operador ponto. Então triple.rgbtBlue, eu posso atribuir que a 0. Verde posso atribuí-lo a full - qualquer número, na verdade, entre 0 e ss. E, em seguida, vermelho, eu também vou dizer a 0. Então isso me dá um pixel verde. Em seguida, o que se eu quiser verificar o valor de alguma coisa? Eu poderia ter algo que verifica se o valor rgbtBlue do triplo é ff e, em seguida, imprimir, "Estou me sentindo azul! ", como um resultado. Agora, isso não significa necessariamente que o pixel é azul, certo? Como os valores verdes e vermelhas do pixels Também pode ter valores não-0. Tudo o que isso significa, e tudo o que este está verificando é para uma cor azul completa. Mas todos os pixels também poderia ter parcial valores de cor, como este próximo exemplo aqui. É um pouco mais difícil de ver o que esta imagem é agora. Isso parece um pouco mais parecido com o clue.bmp que você vai ser dada. Agora, fisicamente, você pode resolver isso, porque há um monte de vermelho, por segurando uma tela vermelha para a imagem de modo que as outras cores podem aparecer. Então, como podemos imitar esta com c? Bem, podemos remover todo vermelho a partir da imagem totalmente. E assim fazer que iríamos definir cada valor vermelho pixel a 0. E assim a imagem ficaria um pouco pouco como este, onde não temos vermelho qualquer. Podemos ver a mensagem de uma oculta pouco mais claramente agora. É mais um rosto sorridente. Ou talvez nós poderíamos usar outro método. Talvez, poderíamos identificar todos os pixels vermelhos - isto é, todos os pixels com 0 azul, verde 0 e 0 vermelho - e mudar aqueles para branco. E a nossa imagem pode parecer algo como isto. Um pouco mais fácil de ver. Há muitas outras maneiras de descobrir a mensagem secreta, bem como, lidar com a manipulação de cor. Talvez você pode usar um dos métodos que eu mencionei acima. E além disso, você pode querer para melhorar algumas cores e levar os para fora. Portanto, agora que nós mudamos o pixel cor, ao lado só precisamos de escrevê-los em que a linha de varredura, pixel por pixel. E mais uma vez, você vai querer olhar para trás para copy.c, se você não copiou já, e olhar para o fwrite função, a qual leva dados, um ponteiro para a estrutura que contém o bytes que você está lendo a partir, o tamanho da os itens, o número de itens, e, em seguida, o outptr - o destino desses arquivos. Depois de escrever nos pixels, você vai também tem que escrever no estofamento. O que é o preenchimento? Bem, cada pixel RGBT é de três bytes. Mas, a linha de varredura de uma imagem de bitmap para tem de ser um múltiplo de quatro bytes. Se o número de pixels não é um múltiplo de quatro, então precisamos adicionar este preenchimento. O preenchimento é apenas representado por 0s. Então, como é que vamos escrever ou ler isso? Bem, acontece que você não pode estofamento realmente fread, mas você pode calculá-lo. Neste caso, a pista eo veredicto têm a mesma largura, de modo que o acolchoamento é a mesma. E o preenchimento, como você verá em copy.c, é calculado com a seguinte fórmula - bi.biWidth vezes sizeof (RGBTRIPLE) vai dê-nos quantos bytes o bmp tem em cada linha. De lá, os modulos e subtrações com 4 pode calcular quanto deve ser adicionado de modo a que muitos bytes o múltiplo de bytes em cada linha é quatro. Agora que temos a fórmula para quanto estofamento que precisamos, agora podemos escrevê-lo. Agora, eu mencionei antes, preenchimento é apenas 0s. Então, nesse caso, estamos apenas colocando char, neste caso, um 0, para o nosso outptr - nosso outfile. Então isso pode ser apenas fputc 0, vírgula outptr. Assim, enquanto nós temos a leitura em nosso arquivo, arquivo I / O tem mantido o controle de nossa posição nesses arquivos com algo chamado o indicador de posição de arquivo. Pense nisso como um cursor. Basicamente, ela avança cada vez que fread, mas temos controle sobre isso, também. Para mover o indicador de posição de arquivo, você pode usar a função fseek. Quando o inptr representa o arquivo ponteiro que você está procurando, em, a montante é o número de bytes que deseja mover o cursor e, em seguida, a partir de refere-se ao ponto de referência a partir de onde está o cursor. Se você passar em SEEK_CUR, que representa o actual posição no arquivo. Ou você pode usar alguns outros parâmetros. Então, a gente pode querer usar fseek para pular sobre o preenchimento do arquivo em. E, novamente, se você está preso, não há um exemplo de que, em copy.c. Então, agora nós abrimos o arquivo, a pista, eo veredicto. Nós atualizamos as informações do cabeçalho para nosso veredicto, porque cada bitmap precisa de um cabeçalho. Então Nós lemos na pista de scanline, pixel a pixel, mudando todas as cores conforme necessário, e escrevendo aqueles no veredicto, pixel por pixel. Uma vez que você abrir o veredicto, você pode ver quem o culpado, ou qual é o segredo mensagem é. Meu nome é Zamyla e este era whodunit.