22"""
33/***************************************************************************
44 ThRasE
5-
5+
66 A powerful and fast thematic raster editor Qgis plugin
77 -------------------
88 copyright : (C) 2019-2025 by Xavier Corredor Llano, SMByC
2424from random import randrange
2525from osgeo import gdal
2626
27+ from qgis .PyQt .QtCore import Qt
2728from qgis .PyQt .QtGui import QColor
28- from qgis .PyQt .QtWidgets import QMessageBox
29+ from qgis .PyQt .QtWidgets import QMessageBox , QProgressDialog , QApplication
2930from qgis .core import QgsPalettedRasterRenderer
3031
3132from ThRasE .utils .qgis_utils import get_file_path_of_layer
@@ -51,14 +52,52 @@ def mask(input_list, boolean_mask):
5152# symbology utils
5253
5354
54- @wait_process
55+ def get_unique_values (layer , band , chunk_size = 1000 ):
56+ """Get unique values in a raster band using chunked GDAL reading"""
57+ gdal_file = gdal .Open (get_file_path_of_layer (layer ), gdal .GA_ReadOnly )
58+ raster_band = gdal_file .GetRasterBand (band )
59+
60+ # Calculate total chunks for progress
61+ x_chunks = (gdal_file .RasterXSize + chunk_size - 1 ) // chunk_size
62+ y_chunks = (gdal_file .RasterYSize + chunk_size - 1 ) // chunk_size
63+ total_chunks = x_chunks * y_chunks
64+
65+ # Create progress dialog
66+ progress = QProgressDialog ("Analyzing raster unique values..." , "Cancel" , 0 , total_chunks )
67+ progress .setWindowTitle ("Processing" )
68+ progress .setWindowModality (Qt .WindowModal )
69+ progress .setMinimumDuration (0 )
70+
71+ unique_values = set ()
72+ chunk_count = 0
73+
74+ # Read in chunks to avoid loading entire raster into memory
75+ for y in range (0 , gdal_file .RasterYSize , chunk_size ):
76+ ysize = min (chunk_size , gdal_file .RasterYSize - y )
77+ for x in range (0 , gdal_file .RasterXSize , chunk_size ):
78+ if progress .wasCanceled ():
79+ gdal_file = None
80+ return []
81+
82+ xsize = min (chunk_size , gdal_file .RasterXSize - x )
83+ chunk = raster_band .ReadAsArray (x , y , xsize , ysize )
84+ unique_values .update (np .unique (chunk ).tolist ())
85+
86+ chunk_count += 1
87+ progress .setValue (chunk_count )
88+ QApplication .processEvents ()
89+
90+ progress .close ()
91+ gdal_file = None # Close the file
92+ return sorted (unique_values )
93+
94+
5595def auto_symbology_classification_render (layer , band ):
5696 # get the unique values in the band
57- rows = layer .height ()
58- cols = layer .width ()
59- provider = layer .dataProvider ()
60- bl = provider .block (band , provider .extent (), cols , rows )
61- unique_values = list (set ([bl .value (r , c ) for r in range (rows ) for c in range (cols )]))
97+ unique_values = get_unique_values (layer , band )
98+
99+ if not unique_values :
100+ return
62101
63102 # fill categories
64103 categories = []
@@ -172,7 +211,7 @@ def safe_call(method, *args):
172211
173212def copy_band_metadata (src , dst ):
174213 """Copy all metadata from source band to destination band
175-
214+
176215 Args:
177216 src: Source GDAL raster band
178217 dst: Destination GDAL raster band
@@ -225,7 +264,7 @@ def copy_band_metadata(src, dst):
225264
226265def copy_dataset_metadata (src , dst ):
227266 """Copy all metadata from source dataset to destination dataset
228-
267+
229268 Args:
230269 src: Source GDAL dataset
231270 dst: Destination GDAL dataset
@@ -248,4 +287,3 @@ def copy_dataset_metadata(src, dst):
248287 gcps = src .GetGCPs ()
249288 if gcps :
250289 safe_call (dst .SetGCPs , gcps , src .GetGCPProjection ())
251-
0 commit comments