diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc old mode 100644 new mode 100755 index 533522913..6fc200a31 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -22,6 +22,8 @@ extern const Settings* settings; CameraConst::CameraConst() { memset(dcraw_matrix, 0, sizeof(dcraw_matrix)); + memset(raw_crop, 0, sizeof(raw_crop)); + memset(raw_mask, 0, sizeof(raw_mask)); white_max = 0; } @@ -96,16 +98,29 @@ CameraConst::parseLevels(CameraConst *cc, int bw, void *ji_) } for (ji = ji->child; ji != NULL; ji = ji->next) { - int iso = 0; + int iso[1000] = { 0 }; + int iso_count = 0; cJSON *js = cJSON_GetObjectItem(ji, "iso"); if (!js) { fprintf(stderr, "missing \"ranges\":\"%s\":\"iso\" object item.\n", bw ? "white" : "black"); return false; - } else if (js->type != cJSON_Number) { - fprintf(stderr, "\"ranges\":\"%s\":\"iso\" must be a a number.\n", bw ? "white" : "black"); + } else if (js->type == cJSON_Number) { + iso[0] = js->valueint; + iso_count = 1; + } else if (js->type == cJSON_Array) { + int i; + for (js = js->child, i = 0; js != NULL && i < 1000; js = js->next, i++) { + if (js->type != cJSON_Number) { + fprintf(stderr, "\"ranges\":\"%s\":\"iso\" must be a number or an array of numbers.\n", bw ? "white" : "black"); + return false; + } + iso[i] = js->valueint; + } + iso_count = i; + } else { + fprintf(stderr, "\"ranges\":\"%s\":\"iso\" must be an array or a number.\n", bw ? "white" : "black"); return false; } - iso = js->valueint; js = cJSON_GetObjectItem(ji, "levels"); if (!js) { fprintf(stderr, "missing \"ranges\":\"%s\":\"levels\".\n", bw ? "white" : "black"); @@ -135,7 +150,9 @@ CameraConst::parseLevels(CameraConst *cc, int bw, void *ji_) fprintf(stderr, "\"ranges\":\"%s\":\"levels\" must be a number or an array of numbers.\n", bw ? "white" : "black"); return false; } - cc->mLevels[bw].insert(std::pair(iso, lvl)); + for (int i = 0; i < iso_count; i++) { + cc->mLevels[bw].insert(std::pair(iso[i], lvl)); + } } return true; } @@ -165,6 +182,44 @@ CameraConst::parseEntry(void *cJSON_, const char *make_model) cc->dcraw_matrix[i] = (short)ji->valueint; } } + ji = cJSON_GetObjectItem(js, "raw_crop"); + if (ji) { + if (ji->type != cJSON_Array) { + fprintf(stderr, "\"raw_crop\" must be an array\n"); + goto parse_error; + } + int i; + for (i = 0, ji = ji->child; i < 4 && ji != NULL; i++, ji = ji->next) { + if (ji->type != cJSON_Number) { + fprintf(stderr, "\"raw_crop\" array must contain numbers\n"); + goto parse_error; + } + cc->raw_crop[i] = ji->valueint; + } + if (i != 4 || ji != NULL) { + fprintf(stderr, "\"raw_crop\" must contain 4 numbers\n"); + goto parse_error; + } + } + ji = cJSON_GetObjectItem(js, "masked_areas"); + if (ji) { + if (ji->type != cJSON_Array) { + fprintf(stderr, "\"masked_areas\" must be an array\n"); + goto parse_error; + } + int i; + for (i = 0, ji = ji->child; i < 8 * 4 && ji != NULL; i++, ji = ji->next) { + if (ji->type != cJSON_Number) { + fprintf(stderr, "\"masked_areas\" array must contain numbers\n"); + goto parse_error; + } + cc->raw_mask[i/4][i%4] = ji->valueint; + } + if (i % 4 != 0) { + fprintf(stderr, "\"masked_areas\" array length must be divisable by 4\n"); + goto parse_error; + } + } jranges = cJSON_GetObjectItem(js, "ranges"); if (jranges) { ji = cJSON_GetObjectItem(jranges, "black"); @@ -236,6 +291,41 @@ CameraConst::get_dcrawMatrix(void) return dcraw_matrix; } +bool +CameraConst::has_rawCrop(void) +{ + return raw_crop[0] != 0 || raw_crop[1] != 0 || raw_crop[2] != 0 || raw_crop[3] != 0; +} + +void +CameraConst::get_rawCrop(int& left_margin, int& top_margin, int& width, int& height) +{ + left_margin = raw_crop[0]; + top_margin = raw_crop[1]; + width = raw_crop[2]; + height = raw_crop[3]; +} + +bool +CameraConst::has_rawMask(int idx) +{ + if (idx < 0 || idx > 7) + return false; + return (raw_mask[idx][0] | raw_mask[idx][1] | raw_mask[idx][2] | raw_mask[idx][3]) != 0; +} + +void +CameraConst::get_rawMask(int idx, int& top, int& left, int& bottom, int& right) +{ + top = left = bottom = right = 0; + if (idx < 0 || idx > 7) + return; + top = raw_mask[idx][0]; + left = raw_mask[idx][1]; + bottom = raw_mask[idx][2]; + right = raw_mask[idx][3]; +} + void CameraConst::update_Levels(const CameraConst *other) { if (!other) diff --git a/rtengine/camconst.h b/rtengine/camconst.h old mode 100644 new mode 100755 index c26ff99f8..cb04c4c49 --- a/rtengine/camconst.h +++ b/rtengine/camconst.h @@ -17,6 +17,8 @@ class CameraConst { private: Glib::ustring make_model; short dcraw_matrix[12]; + int raw_crop[4]; + int raw_mask[8][4]; int white_max; std::map mLevels[2]; std::map mApertureScaling; @@ -32,6 +34,10 @@ class CameraConst { bool has_dcrawMatrix(void); void update_dcrawMatrix(const short *other); const short *get_dcrawMatrix(void); + bool has_rawCrop(void); + void get_rawCrop(int& left_margin, int& top_margin, int& width, int& height); + bool has_rawMask(int idx); + void get_rawMask(int idx, int& top, int& left, int& bottom, int& right); int get_BlackLevel(int idx, int iso_speed); int get_WhiteLevel(int idx, int iso_speed, float fnumber); void update_Levels(const CameraConst *other); diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 5c00bfe21..803e33a56 100755 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -61,7 +61,13 @@ Examples: // ColorMatrix with D65 Calibration Illuminant, in dcraw format "dcraw_matrix": [ 7530, -1942, -255, -4318, 11390, 3362, -926, 1694, 7649 ], // black and white level same for all colors at all ISOs - "ranges": { "black": 10, "white": 1000 } + "ranges": { "black": 10, "white": 1000 }, + // crop away masked sensor borders, 10 pixels left, 20 pixels top, resulting image width/height 4000x3000 + // instead of width/height you can write a negative number which specifies how much of right/bottom border + // that should be removed + "raw_crop": [ 10, 20, 4000, 3000 ], + // same as MaskedAreas DNG tag, used for black level measuring here two areas defined + "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], }, { @@ -500,6 +506,8 @@ Quality X: unknown, ie we knowing to little about the camera properties to know { "make_model": "DummyMake DummyModel", "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], + "raw_crop": [ 10, 20, 4000, 3000 ], + "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], "ranges": { "aperture_scaling": [ { "aperture": 1.2, "scale_factor": 1.1 }, @@ -507,6 +515,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ], "black": [ { "iso": 100 , "levels": [ 10, 20, 10, 20 ] }, + { "iso": [100, 200] , "levels": [ 30, 40, 30 ] }, { "iso": 3200, "levels": [ 50, 60, 50, 60 ] } ], "white": [ diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index cfca38b21..485be7411 100755 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -232,11 +232,41 @@ int RawImage::loadRaw (bool loadData, bool closeFile) fseek (ifp, data_offset, SEEK_SET); (this->*load_raw)(); - if (raw_image) { - crop_masked_pixels(); - free (raw_image); - raw_image=NULL; - } + CameraConstantsStore* ccs = CameraConstantsStore::getInstance(); + CameraConst *cc = ccs->get(make, model); + + if (raw_image) { + if (cc && cc->has_rawCrop()) { + int lm, tm, w, h; + cc->get_rawCrop(lm, tm, w, h); + left_margin = lm; + top_margin = tm; + if (w < 0) { + iwidth += w; + iwidth -= left_margin; + width += w; + width -= left_margin; + } else if (w > 0) { + iwidth = width = w; + } + if (h < 0) { + iheight += h; + iheight -= top_margin; + height += h; + height -= top_margin; + } else if (h > 0) { + iheight = height = h; + } + } + if (cc && cc->has_rawMask(0)) { + for (int i = 0; i < 8 && cc->has_rawMask(i); i++) { + cc->get_rawMask(i, mask[i][0], mask[i][1], mask[i][2], mask[i][3]); + } + } + crop_masked_pixels(); + free (raw_image); + raw_image=NULL; + } // Load embedded profile if (profile_length) { @@ -257,8 +287,6 @@ int RawImage::loadRaw (bool loadData, bool closeFile) */ int black_c4[4] = { -1, -1, -1, -1 }; - CameraConstantsStore* ccs = CameraConstantsStore::getInstance(); - CameraConst *cc = ccs->get(make, model); bool white_from_cc = false; bool black_from_cc = false; if (cc) { @@ -296,6 +324,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile) black_from_cc ? "provided by camconst.json" : "provided by dcraw"); printf("white levels: R:%d G1:%d B:%d G2:%d (%s)\n", get_white(0), get_white(1), get_white(2), get_white(3), white_from_cc ? "provided by camconst.json" : "provided by dcraw"); + printf("raw crop: %d %d %d %d (provided by %s)\n", left_margin, top_margin, iwidth, iheight, (cc && cc->has_rawCrop()) ? "camconst.json" : "dcraw"); printf("color matrix provided by %s\n", (cc && cc->has_dcrawMatrix()) ? "camconst.json" : "dcraw"); } }