Commit 2f33ea8cce30ccffa747f44c1e71b6f4e592f453

Authored by Scott Klum
1 parent 16363df8

Generalized EBTS support

Showing 1 changed file with 108 additions and 42 deletions
openbr/plugins/format.cpp
@@ -780,22 +780,26 @@ BR_REGISTER(Format, scoresFormat) @@ -780,22 +780,26 @@ BR_REGISTER(Format, scoresFormat)
780 class ebtsFormat : public Format 780 class ebtsFormat : public Format
781 { 781 {
782 Q_OBJECT 782 Q_OBJECT
783 -;  
784 - QString textFieldValue(const QByteArray &byteArray, const QString &fieldNumber, int from = 0) const  
785 - {  
786 - // Find the field, skip the number bytes, and account for the semicolon  
787 - int fieldPosition = byteArray.indexOf(fieldNumber, from) + fieldNumber.size() + 1;  
788 - int sepPosition = byteArray.indexOf(QChar(0x1D),fieldPosition);  
789 783
790 - return byteArray.mid(fieldPosition,sepPosition-fieldPosition);  
791 - } 784 + struct Field {
  785 + float type;
  786 + QList<QByteArray> data;
  787 + };
  788 +
  789 + struct Record {
  790 + int type;
  791 + quint32 bytes;
  792 + int position; // Starting position of record
792 793
793 - int recordBytes(const QByteArray &byteArray, const float fieldNumber, int from = 0) const 794 + QList<Field> fields;
  795 + };
  796 +
  797 + quint32 recordBytes(const QByteArray &byteArray, const float recordType, int from) const
794 { 798 {
795 bool ok; 799 bool ok;
796 - int size; 800 + quint32 size;
797 801
798 - if (fieldNumber == 4 || fieldNumber == 7) { 802 + if (recordType == 4 || recordType == 7) {
799 // read first four bytes 803 // read first four bytes
800 ok = true; 804 ok = true;
801 size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData()); 805 size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData());
@@ -807,16 +811,47 @@ class ebtsFormat : public Format @@ -807,16 +811,47 @@ class ebtsFormat : public Format
807 return ok ? size : -1; 811 return ok ? size : -1;
808 } 812 }
809 813
810 - QList<QByteArray> parseRecord(const QByteArray &byteArray, const int from, const int bytes) const 814 + void parseRecord(const QByteArray &byteArray, Record &record) const
811 { 815 {
812 - return byteArray.mid(from,bytes).split(QChar(0x1D).toLatin1()); 816 + if (record.type == 4 || record.type == 7) {
  817 + // Just a binary blob
  818 + // Read everything after the first four bytes
  819 + // Not current supported
  820 + } else {
  821 + // Continue reading fields until we get all the data
  822 + int position = record.position;
  823 + float dataField = .999;
  824 + while (position < record.position + record.bytes) {
  825 + int index = byteArray.indexOf(QChar(0x1D), position);
  826 + Field field = parseField(byteArray.mid(position, index-position),QChar(0x1F));
  827 + if (field.type - dataField == record.type ) {
  828 + // Data begin after the field identifier and the colon
  829 + int dataBegin = byteArray.indexOf(':', position)+1;
  830 + field.data.clear();
  831 + field.data.append(byteArray.mid(dataBegin, record.bytes-(dataBegin-record.position)));
  832 +
  833 + // Data fields are always last in the record
  834 + record.fields.append(field);
  835 + break;
  836 + }
  837 + // Advance the position accounting for the separator
  838 + position += index-position+1;
  839 + record.fields.append(field);
  840 + }
  841 + }
813 } 842 }
814 843
815 - QList<QByteArray> parseField(const QByteArray &byteArray, const QChar &sep) const 844 + Field parseField(const QByteArray &byteArray, const QChar &sep) const
816 { 845 {
817 - QByteArray data = byteArray.split(':').last(); 846 + bool ok;
  847 + Field f;
818 848
819 - return data.split(sep.toLatin1()); 849 + QList<QByteArray> data = byteArray.split(':');
  850 +
  851 + f.type = data.first().toFloat(&ok);
  852 + f.data = data.last().split(sep.toLatin1());
  853 +
  854 + return f;
820 } 855 }
821 856
822 Template read() const 857 Template read() const
@@ -828,40 +863,73 @@ class ebtsFormat : public Format @@ -828,40 +863,73 @@ class ebtsFormat : public Format
828 863
829 Mat m; 864 Mat m;
830 865
  866 + QList<Record> records;
  867 +
831 // Read the type one record (every EBTS file will have one of these) 868 // Read the type one record (every EBTS file will have one of these)
832 - int recordOneBytes = recordBytes(byteArray,1);  
833 - QList<QByteArray> recordOne = parseRecord(byteArray,0,recordOneBytes); 869 + Record r1;
  870 + r1.type = 1;
  871 + r1.position = 0;
  872 + r1.bytes = recordBytes(byteArray,r1.type,r1.position);
  873 +
  874 + // The fields in a type 1 record are strictly defined
  875 + QList<QByteArray> data = byteArray.mid(r1.position,r1.bytes).split(QChar(0x1D).toLatin1());
  876 + foreach (const QByteArray &datum, data) {
  877 + Field f = parseField(datum,QChar(0x1F));
  878 + r1.fields.append(f);
  879 + }
834 880
835 - // The third field (1.03/1.003) will have record identifiers for the remaining  
836 - // portion of the transaction  
837 - QList<QByteArray> recordOneFieldThree = parseField(recordOne.at(2),QChar(0x1F)); 881 + records.append(r1);
838 882
839 - QList<int> recordTypes; 883 + // Read the type two record (every EBTS file will have one of these)
  884 + Record r2;
  885 + r2.type = 2;
  886 + r2.position = r1.bytes;
  887 + r2.bytes = recordBytes(byteArray,r2.type,r2.position);
840 888
841 - for (int i=2; i<recordOneFieldThree.size()-1; i++) /* We don't care about the first two and the final items */ {  
842 - // The first two bytes indicate the record index (and we don't want the separator), but we only care about the type  
843 - QByteArray fieldNumber = recordOneFieldThree[i].mid(3);  
844 - recordTypes.push_back(fieldNumber.toInt()); 889 + // The fields in a type 2 record are strictly defined
  890 + data = byteArray.mid(r2.position,r2.bytes).split(QChar(0x1D).toLatin1());
  891 + foreach (const QByteArray &datum, data) {
  892 + Field f = parseField(datum,QChar(0x1F));
  893 + r2.fields.append(f);
845 } 894 }
846 895
847 - int recordTwoBytes = recordBytes(byteArray,2,recordOneBytes);  
848 - QList<QByteArray> recordTwo = parseRecord(byteArray,recordOneBytes,recordTwoBytes);  
849 -  
850 - QList<int> recordSizes;  
851 - int startingPosition = recordOneBytes + recordTwoBytes;  
852 - foreach(int i, recordTypes) {  
853 - // Maybe switch to position  
854 - int recordSize = recordBytes(byteArray,i,startingPosition);  
855 - qDebug() << i << recordSize;  
856 - recordSizes.append(recordSize);  
857 - startingPosition += recordSize; 896 +
  897 + records.append(r2);
  898 +
  899 + // The third field of the first record contains informations about all the remaining records in the transaction
  900 + // We don't care about the first two and the final items
  901 + for (int i=2; i<r1.fields.at(2).data.size()-1; i++) {
  902 + // The first two bytes indicate the record index (and we don't want the separator), but we only care about the type
  903 + QByteArray recordType = r1.fields.at(2).data[i].mid(3);
  904 + Record r;
  905 + r.type = recordType.toInt();
  906 + records.append(r);
858 } 907 }
859 908
860 - // Parse the remaining records knowing that the first four bytes of types 4 and 7 are sizes 909 + QList<int> frontalIdxs;
  910 + int position = r1.bytes + r2.bytes;
  911 + for (int i=2; i<records.size(); i++) {
  912 + records[i].position = position;
  913 + records[i].bytes = recordBytes(byteArray,records[i].type,position);
861 914
862 - // Win at everything 915 + parseRecord(byteArray, records[i]);
  916 + if (records[i].type == 10) frontalIdxs.append(i);
  917 + position += records[i].bytes;
  918 + }
  919 +
  920 + if (!frontalIdxs.isEmpty()) {
  921 + // We use the first type 10 record
  922 + // Its last field contains the mugshot data (and it will only have one subfield)
  923 + m = imdecode(Mat(3, records[frontalIdxs.first()].fields.last().data.first().size(), CV_8UC3, records[frontalIdxs.first()].fields.last().data.first().data()), CV_LOAD_IMAGE_COLOR);
  924 + if (!m.data) qWarning("ebtsFormat::read failed to decode image data.");
  925 + return Template(m);
  926 + } else {
  927 + qWarning("ebtsFormat::cannot find image data within file.");
  928 + return Template();
  929 + }
863 930
864 // Demographics 931 // Demographics
  932 + /*
865 { 933 {
866 int recordOneSize = recordBytes(byteArray,1); 934 int recordOneSize = recordBytes(byteArray,1);
867 qDebug() << recordBytes(byteArray,1); 935 qDebug() << recordBytes(byteArray,1);
@@ -906,9 +974,7 @@ class ebtsFormat : public Format @@ -906,9 +974,7 @@ class ebtsFormat : public Format
906 int age = current.year() - dob.year(); 974 int age = current.year() - dob.year();
907 if (current.month() < dob.month()) age--; 975 if (current.month() < dob.month()) age--;
908 t.file.set("Age", age); 976 t.file.set("Age", age);
909 - }  
910 -  
911 - return t; 977 + }*/
912 } 978 }
913 979
914 void write(const Template &t) const 980 void write(const Template &t) const