<commit_before>use decoders::RawImage;
use imageops::{OpBuffer,ImageOp,Pipeline};

#[derive(Copy, Clone, Debug)]
pub struct OpLevel {
}

impl OpLevel {
  pub fn new(_img: &RawImage) -> OpLevel {
    OpLevel{}
  }
}

impl ImageOp for OpLevel {
  fn name(&self) -> &str {"level"}
  fn run(&self, pipeline: &Pipeline, buf: &OpBuffer) -> OpBuffer {
    level_and_balance(pipeline.image, buf)
  }
}

pub fn level_and_balance(img: &RawImage, buf: &OpBuffer) -> OpBuffer {
  let mut buf = buf.clone();

  // Calculate the blacklevels
  let mins = img.blacklevels.iter().map(|&x| x as f32).collect::<Vec<f32>>();
  let ranges = img.whitelevels.iter().enumerate().map(|(i, &x)| (x as f32) - mins[i]).collect::<Vec<f32>>();

  let coeffs = if img.is_monochrome() {
    [1.0, 1.0, 1.0, 1.0]
  } else if !img.wb_coeffs[0].is_normal() ||
            !img.wb_coeffs[1].is_normal() ||
            !img.wb_coeffs[2].is_normal() {
    img.neutralwb()
  } else {
    img.wb_coeffs
  };

  // Set green multiplier as 1.0
  let unity: f32 = coeffs[1];
  let mul = coeffs.iter().map(|x| if !x.is_normal() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

  buf.mutate_lines(&(|line: &mut [f32], _| {
    for pix in line.chunks_mut(4) {
      pix[0] = (((pix[0] - mins[0]) / ranges[0]) * mul[0]).min(1.0);
      pix[1] = (((pix[1] - mins[1]) / ranges[1]) * mul[1]).min(1.0);
      pix[2] = (((pix[2] - mins[2]) / ranges[2]) * mul[2]).min(1.0);
      pix[3] = (((pix[3] - mins[3]) / ranges[3]) * mul[3]).min(1.0);
    }
  }));

  buf
}<commit_msg>level: move settings to struct<commit_after>use decoders::RawImage;
use imageops::{OpBuffer,ImageOp,Pipeline};

#[derive(Copy, Clone, Debug)]
pub struct OpLevel {
  blacklevels: [f32;4],
  whitelevels: [f32;4],
  wb_coeffs: [f32;4],
}

impl OpLevel {
  pub fn new(img: &RawImage) -> OpLevel {
    let coeffs = if img.is_monochrome() {
      [1.0, 1.0, 1.0, 1.0]
    } else if !img.wb_coeffs[0].is_normal() ||
              !img.wb_coeffs[1].is_normal() ||
              !img.wb_coeffs[2].is_normal() {
      img.neutralwb()
    } else {
      img.wb_coeffs
    };

    OpLevel{
      blacklevels: [
        img.blacklevels[0] as f32, 
        img.blacklevels[1] as f32, 
        img.blacklevels[2] as f32, 
        img.blacklevels[3] as f32
      ],
      whitelevels: [
        img.whitelevels[0] as f32, 
        img.whitelevels[1] as f32, 
        img.whitelevels[2] as f32, 
        img.whitelevels[3] as f32
      ],
      wb_coeffs: coeffs,
    }
  }
}

impl ImageOp for OpLevel {
  fn name(&self) -> &str {"level"}
  fn run(&self, _pipeline: &Pipeline, buf: &OpBuffer) -> OpBuffer {
    let mut buf = buf.clone();

    // Calculate the levels
    let mins = self.blacklevels;
    let ranges = self.whitelevels.iter().enumerate().map(|(i, &x)| x - mins[i]).collect::<Vec<f32>>();

    // Set green multiplier as 1.0
    let unity: f32 = self.wb_coeffs[1];
    let mul = self.wb_coeffs.iter().map(|x| if !x.is_normal() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

    buf.mutate_lines(&(|line: &mut [f32], _| {
      for pix in line.chunks_mut(4) {
        pix[0] = (((pix[0] - mins[0]) / ranges[0]) * mul[0]).min(1.0);
        pix[1] = (((pix[1] - mins[1]) / ranges[1]) * mul[1]).min(1.0);
        pix[2] = (((pix[2] - mins[2]) / ranges[2]) * mul[2]).min(1.0);
        pix[3] = (((pix[3] - mins[3]) / ranges[3]) * mul[3]).min(1.0);
      }
    }));

    buf
  }
}
{'fraction_non_alphanumeric': 0.2072310405643739, 'fraction_numerical': 0.04262198706643151, 'mean_word_length': 2.7191256830601094, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5485845', 'n_tokens_mistral': 1448, 'n_tokens_neox': 1373, 'n_words': 276}