@GeryKnee ,
here is your lifeline 😀 PUIMG command.
moment before you rush to test it, read this:
i'm not beside my R2006, so the real test is on you.
this command purge all images that has no reference in current drawing. in order to do that, it scans the drawing database which include all blocks and layouts and make a list of all used images to filter them out from the list of images that are exist in Image Dictionary Database. Xrefs (including dependent blocks) are skipped.
After long exploring AutoCAD images i realized that we can not 100% rely on AutoCAD database to return the image name + it's path (the 2 properties this program is rely on) so i put maximum effort to retrieve this data from two direction and if they fail, some images maybe skipped 🤔 and not purged.
at finish PUIMG will notify you how many images were purged.
enjoy
Moshe
(defun c:puimg (/ get_dict_data^ get_images_name _isexist filter_used_images purge_images ; local functions
dict_data^ images_name^ aid^ obj->rel unused^)
; return list of images dictionary data
(defun get_dict_data^ ()
(vl-remove-if
'not
(mapcar
'(lambda (curr / succ)
(if (and
(= (car curr) 3)
(= (car (setq succ (cadr (member curr aid^)))) 350)
)
(cons (strcase (cdr curr)) (strcase (cdr (assoc '1 (entget (cdr succ))))))
)
); lambda
(setq aid^ (dictsearch (namedobjdict) "acad_image_dict"))
); mapcar
); vl-remove-if
); get_dict_data^
; return a list of attached images
(defun get_images_name (/ get_prop _dxd ; local function
AcDbBlockTableRecord AcDbEntity bname path name elist img^)
(defun get_prop (func / str)
(if
(not
(vl-catch-all-error-p
(setq str (vl-catch-all-apply func (list AcDbRasterImage)))
)
)
str
)
); get_prop
; anonymous function
(setq _dxd (lambda (e) (vl-some '(lambda (bit) (= (logand bit (cdr (assoc '70 e))) bit)) '(4 8 16 32 64))))
; scan blocks database
(vlax-for AcDbBlockTableRecord (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
(if (and (setq bname (vla-get-name AcDbBlockTableRecord))
(/= (substr bname 1 2) "*D") ; skip dimension block
(not (_dxd (entget (tblobjname "block" bname)))) ; skip xrefs and dependent blocks
)
; scan objects inside block
(vlax-for AcDbEntity AcDbBlockTableRecord
(if (and
(eq (vla-get-objectName AcDbEntity) "AcDbRasterImage")
(or
(and
(setq path (get_prop 'vla-get-imageFile))
(setq name (get_prop 'vla-get-name))
)
(and
(setq elist (entget (vlax-vla-object->ename AcDbEntity)))
(setq path (cdr (assoc '1 (entget (cdr (assoc '340 elist))))))
(setq name (vl-filename-base path))
)
); or
); and
(if (not (_isexist (setq item (cons (strcase name) (strcase path))) img^))
(setq img^ (cons (cons item img^))
)
); if
(vlax-release-object AcDbEntity)
); vlax-for
); if
(vlax-release-object AcDbBlockTableRecord)
); vlax-for
img^
); get_images_name
; anonymous function, return T if item is already in list
(setq _isexist (lambda (i0 lst) (vl-some '(lambda (i1) (equal i0 i1)) lst)))
; return a list of unsed imgaes
(defun filter_used_images ()
(vl-remove-if
'not
(mapcar
'(lambda (item0)
(if (not (_isexist item0 images_name^))
item0
); if
); lambda
dict_data^
); mapcar
); vl-remove-if
); filter_used_images
; real purge is done here
(defun purge_images (lst / ctr ent)
(setq ctr 0)
(foreach item lst
(if (setq ent (dictremove (cdar aid^) (car item)))
(progn
(entdel ent)
(setq ctr (1+ ctr))
); progn
); if
); foreach
(prompt (strcat "\n" (itoa ctr) " image(s) purged."))
); purge_images
; here start c:puimg
(cond
((not (setq dict_data^ (get_dict_data^)))
; image dictionary data is empty, noting to purge
(prompt "\nNo image(s) found to purge.")
); case
((not (setq images_name^ (get_images_name)))
; No images found in drawing, purge image dictionary data
(purge_images image_data^)
); case
( t
(foreach obj obj->rel (vlax-release-object obj)) ; dispose memory
(if (setq unused^ (filter_used_images))
(purge_images unused^)
; all images is inuse, noting to purge
(prompt "\nNo image(s) found to purge.")
); if
); case
); cond
(princ)
); c:puimg