Generowanie bitmapy w C++ piksel po pikselu

0

Witam

Mam program dzięki któremu generuję sobie tablicę charów. W niej zapisane są hexadecymalnie liczby kolorów kolejno rgb. Chciałbym teraz stworzyć bitmapę w c++ rysując piksel po pikselu, kolorami odpowiadającymi danym z tablicy. Przekopałem dzisiaj szmat internetu i niestety do niczego nie doszedłem. Nie używam jak na razie żadnego WinAPI itd., pracuję w czystej konsoli ;)

Znalazłem taki kod w internecie:

 ifstream we_hex;
        we_hex.open("hex.txt"); //otworzenie pliku w hexie

        const int x=50;
        const int y=50;
        FILE *fp=fopen("obraz.bmp", "wb");
        b.bfType=19778;
        b.bfSize=54+x*y*4;
        b.bfOffBits=1078;
        b.biSize=40;
        b.biWidth=x;
        b.biHeight=y;
        b.biPlanes=1;
        b.biBitCount=24;
        fwrite((char*)&b,1,sizeof(bmp_header), fp);
        for(int tx=0; tx<x;tx++)
        {
                for(int ty=0; ty<y;ty++)
                {
                        static unsigned char color[3];
                        color[0]=tx%255;
                        color[1]=ty%255;
                        color[2]=(tx*ty)%255;
                        fwrite(color, 1, 3, fp);
                }
        }
        fclose(fp);

        we_hex.close();

ale niestety, generuje on obraz tylko i wyłącznie w kolorze czarnym, niezależnie jakie dane mu wpisze. Pomożecie?

1

Zajrzyj tutaj:

http://rosettacode.org/wiki/Bitmap/Write_a_PPM_file#C

W Twoim kodzie i na podanej przeze mnie stronie jest błąd - maksymalna wartość koloru to 255, czyli trzeba
zamiast

color[0]=tx%255;

napisać

color[0]=tx%256;

Edit: poprawiłem to wiki...

0

Tak, tylko kod podany przez Ciebie generuje mi jakieś fraktale O.o I nie do końca rozumiem ten zapis:
(void) fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);

I czy dobrze rozumiem, że kolor zmieniamy w tym miejscu?:

 color[0] = i % 255;  /* red */
color[1] = j % 255;  /* green */
color[2] = (i * j) % 255;  /* blue */
1
Grzesieq94 napisał(a):

Tak, tylko kod podany przez Ciebie generuje mi jakieś fraktale O.o I nie do końca rozumiem ten zapis:
(void) fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);

To jest generacja nagłówka. Jego struktura opisana jest tutaj:
http://netpbm.sourceforge.net/doc/ppm.html

Grzesieq94 napisał(a):

I czy dobrze rozumiem, że kolor zmieniamy w tym miejscu?:

 color[0] = i % 255;  /* red */
color[1] = j % 255;  /* green */
color[2] = (i * j) % 255;  /* blue */

Tak, w tym miejscu generujesz kolejne piksele. Zamień 255 na 256.

0

Ok. Tylko teraz jeśli mam kod:

 #include <stdlib.h>
#include <stdio.h>

int main(void)
{
  const int dimx = 100, dimy = 100;
  int i, j;
  FILE *fp = fopen("first.ppm", "wb"); /* b - binary mode */
  (void) fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);
  for (j = 0; j < dimy; ++j)
  {
    for (i = 0; i < dimx; ++i)
    {
      static unsigned char color[3];
      color[0] = i % 256;  /* red */
      color[1] = j % 256;  /* green */
      color[2] = (i * j) % 256;  /* blue */
      (void) fwrite(color, 1, 3, fp);
    }
  }
  (void) fclose(fp);
  return EXIT_SUCCESS;
}

To generuje mi jakieś dziwne fraktale albo gradienty. Jak wszystkie kolory dałem na 1 to wyszło mi ładne czarne pole. Czyli żeby każdy piksel był innego koloru, muszę generować kolory przy każdym przejściu pętli. A te fraktale wyszły prawdopodobnie dlatego, że akurat tak zmieniały się kolory. Chyba zajarzyłem o co chodzi ;)...

0
Grzesieq94 napisał(a):

Ok. Tylko teraz jeśli mam kod:
To generuje mi jakieś dziwne fraktale albo gradienty. Jak wszystkie kolory dałem na 1 to wyszło mi ładne czarne pole. Czyli żeby każdy piksel był innego koloru, muszę generować kolory przy każdym przejściu pętli. A te fraktale wyszły prawdopodobnie dlatego, że akurat tak zmieniały się kolory. Chyba zajarzyłem o co chodzi ;)...

Żeby wygenerować lepszy gradient:
a) wyznacz wektor w którą stronę chcesz go generować, powiedzmy z pkt A(0,0) do B(99,99).
b) określ jakie chcesz mieć kolory w punktach A i B - red(A), blue(A), green(A) itd...

c) wyznacz odległość maksymalną DM = D(A,B)

d) dla punktu Z(x,y) wyznacz odległość od pkt. A oraz od pkt B

D(A,Z) = sqrt((zx - ax)2 + (zy - ay)2))
D(B,Z) = sqrt((zx - bx)2 + (zy - by)2))

http://www.analyzemath.com/math_problems/distance_solution.html

e) dla punktu Z(x,y) wyznacz odległość względną do punktu A i B:
DW(A,Z) = D(A,Z) / DM
DW(B,Z) = D(B,Z) / DM

f) kolor który będzie podobny w stopniu DW(A,Z) to koloru A i DW(B,Z) do koloru B

czyli

red(Z) = red(A) * (1 - DW(A,Z)) + red(B) * (1 - DW(B,Z))
blue(Z) = blue(A) * (1 - DW(A,Z)) + blue(B) * (1 - DW(B,Z))
green(Z)...

Na podstawie:
http://dminator.blogspot.com/2007/09/gradient-calculation-explained.html

0

Właśnie gradient był tutaj zjawiskiem nieporządanym ;) Ja chciałem dla każdego piksela wygenerować kolor z odpowiedniego zapisu w hexie.

Np. mam zapis 4c6f72 to chciałbym z niego zrobić color[1]=76; (bo 4c to w zapisie decymalnym jest 76) color[2]=111; color[3]=114;
Nie wiem dlaczego, ale jak tak podstawiam liczby to pod koniec tworzenia pliku wywala mi FC :/

0
Grzesieq94 napisał(a):

Właśnie gradient był tutaj zjawiskiem nieporządanym ;) Ja chciałem dla każdego piksela wygenerować kolor z odpowiedniego zapisu w hexie.

Np. mam zapis 4c6f72 to chciałbym z niego zrobić color[1]=76; (bo 4c to w zapisie decymalnym jest 76) color[2]=111; color[3]=114;
Nie wiem dlaczego, ale jak tak podstawiam liczby to pod koniec tworzenia pliku wywala mi FC :/

Czyli teraz potrzebujesz hasła "C++ read hex file".
Znalezione nie kradzione:
http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/02e2c4e3-96fc-4341-88c2-d68b7f069e1c

(fileData to wektor linijek twojego pliku wejściowego, każda linijka to zbiór bajtów).

0

Stworzyłem sobie sam funkcję która przelicza mi hex na dec:

 int hex_dec(char x, char y) //Funkcja przeliczajaca hex (tablica char[2] na inta 0-255 dla koloru
{
    char dane[2];
    dane[0]=x;
    dane[1]=y;
    int wynik=0;
    int a=0;
    int b=0;

    if(dane[0]=='1') a=1*16;    //obliczanie pierwszej czesci hexa
    if(dane[0]=='2') a=2*16;
    if(dane[0]=='3') a=3*16;
    if(dane[0]=='4') a=4*16;
    if(dane[0]=='5') a=5*16;
    if(dane[0]=='6') a=6*16;
    if(dane[0]=='7') a=7*16;
    if(dane[0]=='8') a=8*16;
    if(dane[0]=='9') a=9*16;
    if(dane[0]=='a') a=10*16;
    if(dane[0]=='b') a=11*16;
    if(dane[0]=='c') a=12*16;
    if(dane[0]=='d') a=13*16;
    if(dane[0]=='e') a=14*16;
    if(dane[0]=='f') a=15*16;

    if(dane[1]=='1') b=1;   //obliczanie drugiej czesci hexa
    if(dane[1]=='2') b=2;
    if(dane[1]=='3') b=3;
    if(dane[1]=='4') b=4;
    if(dane[1]=='5') b=5;
    if(dane[1]=='6') b=6;
    if(dane[1]=='7') b=7;
    if(dane[1]=='8') b=8;
    if(dane[1]=='9') b=9;
    if(dane[1]=='a') b=10;
    if(dane[1]=='b') b=11;
    if(dane[1]=='c') b=12;
    if(dane[1]=='d') b=13;
    if(dane[1]=='e') b=14;
    if(dane[1]=='f') b=15;

    wynik=a+b;  //obliczanie wyniku

    return wynik;   //zwracanie wyniku w integerze
}

Tak wiem, uboga, ale na razie lepszej mi nie potrzeba. Pod colory podstawiam coś takiego:

c = hex_dec(kolor[ii],kolor[ii+1]);
              color[0] = c;  /* red */
              ii=ii+2;
              c = hex_dec(kolor[ii],kolor[ii+1]);
              color[1] = c;  /* green */
              ii=ii+2;
              c = hex_dec(kolor[ii],kolor[ii+1]);
              color[2] = c;  /* blue */
              ii=ii+2; 

Ale cosik nie trybi. Zmienna ii jest po to aby odczytywać kolejne znaki z tablicy. hex_dec z dwóch znaków hex oblicza wartość w int i wrzucam ją do zmiennej c. Zmienną c umieszczam w tablicy color, ale po "przeleceniu" całej tablicy z hexem wywala mi FC.

EDIT: Ok, już widzę, że źle generuje mi się c, tylko jeszcze nie wiem dlaczego ;)
EDIT2: Jak wywalam coutem te liczby to wypisuje mi po kolei odpowiadające danemu kodowi litery. Tak więc gdzieś zmiana typu przerzuca mi liczbę na literę :/
EDIT3: Już poradziłem sobie z zmianą typów, plik się generuje, ale niestety dalej mam błędy. Pierwsza składowa koloru generuje się elegancko. Natomiast dwie następne już nie :/ Nie mam pojęcia dlaczego. Są one generowane identycznie jak pierwsza.

Błąd jest w obrębie tego kodu:

 (void) fwrite(color, 1, 3, fp);

Gdy jest standardowo wpisuje tylko jeden kolor (czerwony), gdy zmienię na:

 (void) fwrite(color, 3, 3, fp);

To wczytuje wszystkie kolory, ale jako osobne 3 piksele. Nie potrafi do jednego piksela przypisać więcej niż jednego koloru :/

Aktualnie tak wygląda wypełnianie pliku:

 static int color[3];
              c = hex_dec(kolor[ii],kolor[ii+1]);
              color[0] = c;  /* red */
              cout << "c: " << c << " ii: " << ii << " color[" << i << "]: " << color[0] << endl;
              //getch();
              ii=ii+2;
              c = 0;
              c = hex_dec(kolor[ii],kolor[ii+1]);
              color[1] = c;  /* green */
              cout << "c: " << c << " ii: " << ii << " color[" << i << "]: " << color[1] << endl;
              //getch();
              ii=ii+2;
              c = 0;
              c = hex_dec(kolor[ii],kolor[ii+1]);
              color[2] = c;  /* blue */
              cout << "c: " << c << " ii: " << ii << " color[" << i << "]: " << color[2] << endl;
              //getch();
              ii=ii+2;
              (void) fwrite(color, 1, 3, fp);

Tyle, że zmiana typu tablicy color z static unsigned char na static int chyba nie wyszła na dobre wpisywaniu pikseli do pliku :( Nie mam pojęcia jak to wszystko zebrać do kupy. Dziś sobie chyba odpuszczę bo już dziś długo nad tym siedziałem. Mam nadzieję, że wy widzicie gdzieś jakieś błędy :)

2

Ten Twój hex_dec to taki chłopak do bicia... Na dobry początek zamień go tak:

int hex2dec1(char x)
{
  if (x <= '9')
    return x - '0';
  else if (x <= 'F')
    return x - 'A' + 10;
  else if (x <= 'f')
    return x - 'a' + 10;
  else
    return -1;
}

int hex_dec(char x, char y)
{
   int a = hex2dec1(x)
   int b = hex2dec1(y);
   if ((a >= 0) && (b >= 0))
     return (a << 4) + b;
   else
     return -1;
}

A potem podaj cały kod, coś gdzieś źle przekazujesz pewnie.

0

Już sobie ładnie poradziłem i wszystko mi się generuje. Po prostu źle rzutowałem typy między intem i unsigned charem i do c wrzucało mi znaki zamiast odpowiadającym im liczbom. http://szablony.freeware.info.pl/background.html Dzięki za pomoc ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1