@@ -11,6 +11,7 @@ use cosmic::{
1111 widget:: { self , Space , column, icon, row, settings, text} ,
1212} ;
1313use cosmic_settings_page:: { self as page, Section , section} ;
14+ use image:: GenericImageView ;
1415use pwhash:: { bcrypt, md5_crypt, sha256_crypt, sha512_crypt} ;
1516use regex:: Regex ;
1617use slab:: Slab ;
@@ -20,7 +21,7 @@ use std::{
2021 fs:: File ,
2122 future:: Future ,
2223 io:: { BufRead , BufReader } ,
23- path:: PathBuf ,
24+ path:: { Path , PathBuf } ,
2425 sync:: Arc ,
2526} ;
2627use url:: Url ;
@@ -29,6 +30,14 @@ use zbus_polkit::policykit1::CheckAuthorizationFlags;
2930const DEFAULT_ICON_FILE : & str = "/usr/share/pixmaps/faces/pop-robot.png" ;
3031const USERS_ADMIN_POLKIT_POLICY_ID : & str = "com.system76.CosmicSettings.Users.Admin" ;
3132
33+ // AccountsService has a hard limit of 1MB for icon files
34+ // https://gitlab.freedesktop.org/accountsservice/accountsservice/-/blob/main/src/user.c#L3131
35+ const MAX_ICON_SIZE_BYTES : u64 = 1_048_576 ;
36+ // Use a smaller threshold to ensure compressed images stay under the limit
37+ const ICON_SIZE_THRESHOLD : u64 = 900_000 ; // 900KB
38+ // Target dimensions for resized profile icons
39+ const TARGET_ICON_SIZE : u32 = 512 ;
40+
3241#[ derive( Clone , Debug , Default ) ]
3342pub struct User {
3443 id : u64 ,
@@ -124,6 +133,58 @@ impl From<Message> for crate::pages::Message {
124133 }
125134}
126135
136+ fn prepare_icon_file ( path : & Path ) -> Result < PathBuf , Box < dyn std:: error:: Error > > {
137+ let metadata = std:: fs:: metadata ( path) ?;
138+ let file_size = metadata. len ( ) ;
139+
140+ tracing:: debug!( "Icon file size: {} bytes" , file_size) ;
141+
142+ if file_size <= ICON_SIZE_THRESHOLD {
143+ tracing:: debug!( "File size is acceptable, using original file" ) ;
144+ return Ok ( path. to_path_buf ( ) ) ;
145+ }
146+
147+ tracing:: info!(
148+ "Icon file is {} bytes, resizing to fit under 1MB limit" ,
149+ file_size
150+ ) ;
151+
152+ let img = image:: open ( path) ?;
153+ let ( width, height) = img. dimensions ( ) ;
154+
155+ tracing:: debug!( "Original image dimensions: {}x{}" , width, height) ;
156+
157+ let ( new_width, new_height) = if width > height {
158+ let ratio = TARGET_ICON_SIZE as f32 / width as f32 ;
159+ ( TARGET_ICON_SIZE , ( height as f32 * ratio) as u32 )
160+ } else {
161+ let ratio = TARGET_ICON_SIZE as f32 / height as f32 ;
162+ ( ( width as f32 * ratio) as u32 , TARGET_ICON_SIZE )
163+ } ;
164+
165+ tracing:: debug!( "Resizing to {}x{}" , new_width, new_height) ;
166+
167+ let resized = img. resize ( new_width, new_height, image:: imageops:: FilterType :: Lanczos3 ) ;
168+
169+ // Create a temporary file for the resized icon
170+ let temp_dir = std:: env:: temp_dir ( ) ;
171+ let temp_filename = format ! ( "cosmic-settings-icon-{}.png" , std:: process:: id( ) ) ;
172+ let temp_path = temp_dir. join ( temp_filename) ;
173+
174+ tracing:: debug!( "Saving resized icon to: {:?}" , temp_path) ;
175+
176+ resized. save ( & temp_path) ?;
177+
178+ let new_size = std:: fs:: metadata ( & temp_path) ?. len ( ) ;
179+ tracing:: info!( "Resized icon file size: {} bytes" , new_size) ;
180+
181+ if new_size > MAX_ICON_SIZE_BYTES {
182+ tracing:: warn!( "Resized file is still too large, but attempting anyway" ) ;
183+ }
184+
185+ Ok ( temp_path)
186+ }
187+
127188impl page:: Page < crate :: pages:: Message > for Page {
128189 fn set_id ( & mut self , entity : page:: Entity ) {
129190 self . entity = entity;
@@ -466,8 +527,17 @@ impl Page {
466527 return Message :: None ;
467528 } ;
468529
530+ // Prepare the icon file, resizing if necessary to fit within accountsservice's 1MB limit
531+ let icon_path = match prepare_icon_file ( & path) {
532+ Ok ( p) => p,
533+ Err ( why) => {
534+ tracing:: error!( ?why, "failed to prepare icon file" ) ;
535+ return Message :: None ;
536+ }
537+ } ;
538+
469539 let result = request_permission_on_denial ( & conn, || {
470- user. set_icon_file ( path . to_str ( ) . unwrap ( ) )
540+ user. set_icon_file ( icon_path . to_str ( ) . unwrap ( ) )
471541 } )
472542 . await ;
473543
0 commit comments