Как известно, фотографии со спутника «Электро-Л» выкладываются на FTP в двух форматах.
Один — общеизвестный jpg, который нам не интересен.
Второй, как писал Zelenyikot
«секретный» формат доступный только метеорологам. В сети нет ПО, которое позволяет его открыть и посмотреть. Правда меня заверили, что с точки зрения картинки, там то же самое, что и на JPEG, а дополнительная информация только текстом – всякие там, высоты, температуры, скорости…
Вот его мы и попытается прочитать.
Дополнительную информацию у меня прочитать не получилось, зато картинка вполне читаема, и она несколько отличается от той, что в JPG, по количеству бит на единственный канал. Если в JPG их 8 (256 оттенков серого), то в L15 их 10 (1024 оттенка серого).
Если изображение в файле не зашифровано, то в нём должны встречаться размеры изображения. Будем надеяться, что оно не зашифровано.
Размеры изображения у фотографий со спутника в формате jpg 2784x2784. Переведя 2784 в HEX получим 0A E0. Эту последовательность надо перевернуть и искать E0 0A
Нашлось
e0 0a 00 00 e0 0a 00 00 10 00Сгруппировав эти данные по 4 байта и отобразив как десятичное число получим
2784 2784 16От конца блока, вставленного чуть выше до конца файла 0xEC8800 (15501312) байт.
15501312/(2784*2784)=2. Из этих результатов предположим, что один пиксель описывается двумя байтами.
Но прежде чем пытаться прочитать изображение надо понять, как искать место, с которого оно начинается.
Два дня поисков в файлах L15 либо прямого адреса области с изображением или близкого к нему участка, либо смещения на этот адрес к успеху не привели.
Поэтому, будем искать этот участок «в лоб», читатя файл бит за битом до тех пор, пока не встретится число 2784 или 11136(это разрешение изображений от каналов R G B).
После чего проверяем, повторяется ли это число ещё раз, и, если оно повторяется, проверяем, равняется ли следующее число 16.
Если всё верно, поздравляю, мы нашли начало картинки.
long Find_Image_Pos(FILE *EL_Data,int *res_out) { unsigned int int_data; int resolution; unsigned long filepos; filepos=0; while(!feof(EL_Data)) { fseek(EL_Data,filepos,SEEK_SET); fread((void*)&int_data,sizeof(unsigned int),1,EL_Data); if(int_data==2784||int_data==11136) { resolution=int_data; fread((void*)&int_data,sizeof(unsigned int),1,EL_Data); if(int_data==resolution) { fread((void*)&int_data,sizeof(unsigned int),1,EL_Data); if(int_data==16) { *res_out=resolution; return ftell(EL_Data); } } } filepos++; } return 0; }
Метод костыльный, но пока ошибок не давал.
Теперь нужно прочитать это изображение и как-то его отобразить или сохранить в файл. Так как с изображениями мне работать не приходилось, то для ускорения процесса и облегчения кода я решил использовать формат Portable anymap.
Будем читать файл по 2 байта и записывать считанное значение в файл. void Save_Image(FILE *EL_Data,FILE *EL_Image,long pos,int resolution) { #ifdef P5 char header[50]; sprintf(header,"P5\n%i %i\n1024\n",resolution,resolution); fwrite(&header,strlen(header),1,EL_Image); #else fprintf(EL_Image,"P2\n%i %i\n1024\n",resolution,resolution); #endif int progress=-1; int max=0; int x=0,y=0; int pixel=0; fseek(EL_Data,pos,SEEK_SET); for(y=0;y<resolution;y++) { if(progress<(y*100/resolution)) { progress=(y*100/resolution); cout<<progress<<"%"<<endl; } for(x=0;x<resolution;x++) { fread(&pixel,2,1,EL_Data); #ifdef P5 fwrite(&pixel,1,1,EL_Image); #else fprintf(EL_Image,"%i\n",pixel); #endif if(pixel>max) max=pixel; } } cout<<"100 %"<<endl; cout<<"max="<<max<<endl; }
В формате P5, пиксели, яркость которых больше 255 (то есть больше 1-го байта) становятся чёрными.
Результат:
P2:

P5

И на последок код, который соеденяет вышенаписанные функции
#include <iostream>; #include <stdio.h> #include <tchar.h> #include <stdlib.h> #include <windows.h> //#define P5 using namespace std; long Find_Image_Pos(FILE *EL_Data,int *res_out); void Save_Image(FILE *EL_Data,FILE *EL_Image,long pos,int resolution); int _tmain(int argc, _TCHAR* argv[]) { FILE *EL_Data,*EL_Image; if(argc==1) return 0; EL_Data=_wfopen(argv[1],L"rb"); if(!EL_Data) return 0; wchar_t out_file[300]; #ifdef P5 wsprintf(out_file,L"%s.P5.pgm",argv[1]); EL_Image=_wfopen(out_file,L"wb"); #else wsprintf(out_file,L"%s.P2.pgm",argv[1]); EL_Image=_wfopen(out_file,L"wt"); #endif if(!EL_Image) return 0; int resolution=0; long pos=Find_Image_Pos(EL_Data,&resolution); if(!pos) return 0; Save_Image(EL_Data,EL_Image,pos,resolution); fclose(EL_Image); fclose(EL_Data); return 0; }
Изображения с глубиной цвета 10 бит на канал можно использовать для создания HDRi изображений. Впрочем, это уже тема отдельного топика.
UPD: Есть подозрение, что текстовые данные хранятся в формате wchar. Надо будет проверить…

