Nickolay.info. Алгоритмы. Чтение и запись формата PCX на Си |
Был некогда такой популярный графический формат, поддерживал до 256 цветов, паковал данные построчно. Приложенная ниже демка содержит функции для чтения и записи 256-цветных правильно запакованных файлов PCX. Запускать её нужно с одним или двумя параметрами, переданными через командную строку, например, так:
pcx256 test.pcx result.pcx
Как и любые графические DOS-программы, работать демка будет только из-под эмулятора, такого как DOSbox.
Конечно, демка в данном случае запишет то же, что прочитала, но метод WritePCX
может писать и любую нужную область с экрана.
Вот файл test.pcx (новое окно). Не знаю, покажет ли его Ваш браузер. Стандартные графические программы офиса точно это умеют.
test.pcx (13 Кб)
#include <stdio.h> #include <alloc.h> typedef struct pcxheader { char manuf; char hard; char endcod; char bitpx; int x1,y1,x2,y2; int hres,vres; char clrma[48]; char vmode; char nplanes; int bplin; int palinfo; int shres,svres; int xtra[54]; } PCXHEADER; void putpixel (int X, char Y, char C) { // Устанавливает пиксел (X,Y) в цвет Color asm mov bx,X; asm mov cl,Y; asm mov dl,C; asm mov ax,0a000h; asm mov es,ax; asm mov al,0a0h; asm mul cl; asm add ax,ax; asm add bx,ax; asm mov [es:bx],dl; return; } char getpixel (int X, char Y) { // Возвращает цвет пиксела (X,Y) asm mov bx,X; asm mov cl,Y; asm mov ax,0a000h; asm mov es,ax; asm mov al,0a0h; asm mul cl; asm add ax,ax; asm add bx,ax; asm mov al,[es:bx]; return (_AL); } void setpalette (int Num,char R_, char G_, char B_) { asm mov ax,0x1010; asm mov bx,Num; asm mov dh,R_; asm mov ch,G_; asm mov cl,B_; asm int 10h; return; } void getpalette (int Num,char *R_, char *G_, char *B_) { char R,G,B; asm mov ax,0x1015; asm mov bx,Num; asm int 10h; asm mov R,dh; asm mov G,ch; asm mov B,cl; *R_=R; *G_=G; *B_=B; return; } char Table[768]; void setallpalette (void) { asm push es; asm mov ax, seg Table; asm mov es,ax; asm mov dx, offset Table; asm mov ax, 0x1012; asm mov bx,0; asm mov cx,256; asm int 10h; asm pop es; return; } void getallpalette (void) { asm push es; asm mov ax, seg Table; asm mov es,ax; asm mov dx, offset Table; asm mov ax, 0x1017; asm mov bx,0; asm mov cx,256; asm int 10h; asm pop es; return; } static PCXHEADER header; FILE *fp; unsigned char WritePCX (int x1,int y1,int x2,int y2,char *fname) { // Возвращает 0 в случае успеха // 1 - ошибка открытия файла // 3 - ошибка записи в файл // 11 - нет памяти для буферов int y,x,i,len=128; unsigned char *buffer, *mb, *pack_buffer, *mpb; int buf_full,pack_count; unsigned char rep,cur_byte,Ten=0x0C,R,G,B; fp=fopen(fname,"wb"); if (fp==NULL) return 1; header.manuf=0x0A; header.hard=5; header.endcod=1; header.bitpx=8; header.x1=x1; header.y1=y1; header.x2=x2; header.y2=y2; header.hres=0; header.vres=0; header.vmode=0x13; header.nplanes=1; header.bplin=320; header.palinfo=1; for (i=0; i<16; i++) { // Палитра 16 цветов getpalette (i,&R, &G, &B); header.clrma[3*i]=R<<2; header.clrma[3*i+1]=G<<2; header.clrma[3*i+2]=B<<2; } i=fwrite (&header,1,len,fp); if (!i) return -2; buffer=(unsigned char *)malloc(320); pack_buffer=(unsigned char *)malloc(640); //Размер "упакованного" м.б. в 2 раза больше, если исп.цвета старше 191 //без повторений if ((buffer==NULL)||(pack_buffer==NULL)) return 11; for (y=y1;y<=y2;y++) { for (x=x1; x<=x2; x++) buffer[x-x1]=getpixel (x,y); mb=buffer; mpb=pack_buffer; buf_full=x2-x1+1; pack_count=0; for (;;) { if (buf_full==0) break; cur_byte=*mb++; rep=1; buf_full--; while ((*mb==cur_byte)&&(buf_full>0)) { mb++; rep++; buf_full--; if (buf_full==0) break; //Пакуем построчно; //Иначе в этом месте обновление буфера if (rep==63) break; } if (rep>1) { *mpb=(0xC0|rep); mpb++; *mpb=cur_byte; mpb++; pack_count+=2; } else if (cur_byte<0xC0) { *mpb=cur_byte; mpb++; pack_count++; } else { *mpb=0xC1; mpb++; *mpb=cur_byte; mpb++; pack_count+=2; } } i=fwrite (pack_buffer,1,pack_count,fp); if (!i) return 3; } fwrite (&Ten,1,1,fp); getallpalette(); // Палитра 256 цветов for (i=0; i<768; i++) (Table[i])<<=2; fwrite (&Table[0],768,1,fp); fclose (fp); free (buffer); free (pack_buffer); return 0; } unsigned char ReadPCX (char *fname) { // Возвращает 0 в случае успеха // 1 - ошибка открытия файла // 4 - ошибка чтения из файла // 11 - нет памяти для буферов int k,n,y,l,rest,rep_count=0,len=128,xpos; char ypos; unsigned char *planes,*buffer,*b,c,bits,Ten,R,G,B; fp=fopen(fname,"rb"); if (fp==NULL) return 0x01; buffer=(unsigned char *)malloc(120); planes=(unsigned char *)malloc(3840); //Макс. сжатие 120 байт - в 32 раза, т.е. 3840 байт if ((buffer==NULL)||(planes==NULL)) return 11; l=fread (&header,len,1,fp); if (!l) return 0x04; fseek (fp,-769L,SEEK_END); fread (&Ten,1,1,fp); if (Ten==0x0A || Ten==0x0C) { // Получить палитру fread (&Table[0],768,1,fp); for (l=0; l<768; l++) { if (Ten==0x0C) (Table[l])>>=2; else (Table[l])&=0x3f; } setallpalette (); } fseek (fp,len,SEEK_SET); rest=fread (buffer,1,120,fp); b=buffer; xpos=header.x1; ypos=(unsigned char)header.y1; for (y=header.y1; y<=header.y2; y++) { //header.nplanes*header.bplin; for (k=0; k<header.bplin; k+=rep_count) { if (rest==0) { rest=fread (buffer,1,120,fp); b=buffer; } c=b[0]; b++; rest--; if ((c&0xC0)==0xC0) { rep_count=(c&0x3F); if (rest==0) { rest=fread (buffer,1,120,fp); b=buffer; } bits=(*b); b++; rest--; } else { rep_count=1; bits=c; } for (l=0;l<rep_count;l++) planes[k+l]=bits; } for (l=0; l<k; l++) { if (xpos>header.x2) { xpos=header.x1; ypos++; if (ypos>header.y2) { ypos--; xpos=header.x2+1; break; } } putpixel (xpos,ypos,planes[l]); xpos++; } } free (planes); free (buffer); fclose (fp); return 0; } #include <stdlib.h> void main(int argc, char *argv[]) { int i,j; asm { mov ax,0013h; int 10h; } // for (i=0;i<320;i++) // for (j=0;j<200;j++) putpixel (i,j,(i+j)%256); if (argc>1) { i=ReadPCX (argv[1]); if (i) { printf ("\n Error %d",i); return; } //getallpalette(); /* for (i=0; i<768; i++) { Table[i]=i%64; } */ //setallpalette(); //WritePCX (0,0,319,199,"!.pcx"); //!!! } if (argc>2) { WritePCX (0,0,319,199,argv[2]); } /* else { WritePCX (0,0,319,199,"!.pcx"); for (i=0;i<320;i++) for (j=0;j<200;j++) putpixel (i,j,0); ReadPCX ("!.pcx"); } */ getchar(); asm { mov ax,0003h; int 10h; } return; }
гостевая; E-mail |