Repository: tauri-apps/tauri
File: crates/tauri-cli/src/icon.rs (Rust)

Code before:
        for pixel in buf.pixels_mut() {
          let a = pixel[3] as u32;
          pixel[0] = ((pixel[0] as u32 * a + 127) / 255) as u8;
          pixel[1] = ((pixel[1] as u32 * a + 127) / 255) as u8;
          pixel[2] = ((pixel[2] as u32 * a + 127) / 255) as u8;
        }
        let premultiplied = DynamicImage::ImageRgba8(buf);

        // Step 2: Resize
        let mut resized = premultiplied.resize_exact(size, size, FilterType::Lanczos3).to_rgba8();

        // Step 3: Unpremultiply alpha and zero RGB for fully transparent
        for pixel in resized.pixels_mut() {
          let a = pixel[3] as u32;
          if a == 0 {
            pixel[0] = 0;
            pixel[1] = 0;
            pixel[2] = 0;
          } else {
            pixel[0] = ((pixel[0] as u32 * 255 + a / 2) / a).min(255) as u8;
            pixel[1] = ((pixel[1] as u32 * 255 + a / 2) / a).min(255) as u8;
            pixel[2] = ((pixel[2] as u32 * 255 + a / 2) / a).min(255) as u8;
          }
        }
        Ok(DynamicImage::ImageRgba8(resized))
      }
    }
  }
}

fn read_source(path: PathBuf) -> Result<Source> {
  if let Some(extension) = path.extension() {
    if extension == "svg" {
      let rtree = {
        let mut fontdb = usvg::fontdb::Database::new();
        fontdb.load_system_fonts();

        let opt = usvg::Options {
          // Get file's absolute directory.
          resources_dir: std::fs::canonicalize(&path)
            .ok()
            .and_then(|p| p.parent().map(|p| p.to_path_buf())),
          fontdb: Arc::new(fontdb),
          ..Default::default()
        };

        let svg_data = std::fs::read(&path).unwrap();
        usvg::Tree::from_data(&svg_data, &opt).unwrap()
      };

      Ok(Source::Svg(rtree))

Review comment (suggestion):
```suggestion
      Self::DynamicImage(image) => {
        // Premultiply alpha
        let premultiplied_image = DynamicImage::ImageRgba8(ImageBuffer::from_par_fn(
          image.width(),
          image.height(),
          |x, y| {
            let mut pixel = image.get_pixel(x, y);
            let alpha = pixel.0[3] as f32 / u8::MAX as f32
            pixel.apply_without_alpha(|channel_value| (channel_value as f32 * alpha) as u8);
            pixel
          },
        ));

        let mut resized = premultiplied_image.resize_exact(size, size, FilterType::Lanczos3);

        // Unmultiply alpha
        resized
          .as_mut_rgba8()
          .unwrap()
          .par_pixels_mut()
          .for_each(|pixel| {
            let alpha = pixel.0[3] as f32 / u8::MAX as f32
            pixel.apply_without_alpha(|channel_value| (channel_value as f32 / alpha) as u8);
          });

        Ok(resized)
      }
```

We should be able to rayon here to speed up the process

(the code needs adding rayon to `Cargo.toml` and import `use rayon::iter::ParallelIterator;`)

Also, a comment with a link (for example https://github.com/image-rs/image/issues/1655 or the issue #14351) and some reasoning behind this would be nice

Code after:
        // see https://github.com/image-rs/image/issues/1655
        //
        // image.resize_exact(size, size, FilterType::Lanczos3)

        // Premultiply alpha
        let premultiplied_image =
          ImageBuffer::from_par_fn(image.width(), image.height(), |x, y| {
            let mut pixel = image.get_pixel(x, y);
            let alpha = pixel.0[3] as f32 / u8::MAX as f32;
            pixel.apply_without_alpha(|channel_value| (channel_value as f32 * alpha) as u8);
            pixel
          });

        let mut resized =
          image::imageops::resize(&premultiplied_image, size, size, FilterType::Lanczos3);

        // Unmultiply alpha
        resized.par_pixels_mut().for_each(|pixel| {
          let alpha = pixel.0[3] as f32 / u8::MAX as f32;
          pixel.apply_without_alpha(|channel_value| (channel_value as f32 / alpha) as u8);
        });

        Ok(DynamicImage::ImageRgba8(resized))
      }
    }
  }
}

fn read_source(path: PathBuf) -> Result<Source> {
  if let Some(extension) = path.extension() {
    if extension == "svg" {
      let rtree = {
        let mut fontdb = usvg::fontdb::Database::new();
        fontdb.load_system_fonts();

        let opt = usvg::Options {
          // Get file's absolute directory.
          resources_dir: std::fs::canonicalize(&path)
            .ok()
            .and_then(|p| p.parent().map(|p| p.to_path_buf())),
          fontdb: Arc::new(fontdb),
          ..Default::default()
        };

        let svg_data = std::fs::read(&path).unwrap();
        usvg::Tree::from_data(&svg_data, &opt).unwrap()
      };

      Ok(Source::Svg(rtree))
    } else {
      Ok(Source::DynamicImage(DynamicImage::ImageRgba8(