Purge Unused Raster Image Reference

Purge Unused Raster Image Reference

GeryKnee
Advocate Advocate
5,141 Views
21 Replies
Message 1 of 22

Purge Unused Raster Image Reference

GeryKnee
Advocate
Advocate

Hello to everyone.

I come back to my previous "purge all unused AcDbRasterImageDef entities" Post.

Problem ::

 I atach an image for example "C:\Users\Gery\Desktop\ACAD\[Problem]\Purge Unused Raster Image Reference\MyRemovedJpgXRef.jpg"

 I save the drawing document.

 I Quit Autocad

 I Restart Autocad by opening the previous document

 I delete the imade reference. The document now does'n include the image xref object.

 I save the drawing document.

 I Quit Autocad

 I Restart Autocad by opening the previous document

 I export document as DXF format text

 I open the exported DXF 

 Opening DXF using notepad

 I see those lines :::

..............
AcDbDictionary
281
1
3
MyRemovedJpgXRef
350
264
0
................
AcDbRasterImageDef
90
0
1
C:\Users\Gery\Desktop\ACAD\[Problem]\Purge Unused Raster Image Reference\MyRemovedJpgXRef.jpg
10
253.0
20
165.0
11
.................

 That is causing many problems with document. Those problems I described in my first post.

 Is there a solution to purge eny LIBRARY REFERENCE to a DELETED XREF REFERENCE as can be purged unsused BLOCK REFERNCED ?????

Thanks,

Gery

 

0 Likes
Accepted solutions (2)
5,142 Views
21 Replies
Replies (21)
Message 2 of 22

Moshe-A
Mentor
Mentor

@GeryKnee ,

 

 I delete the image reference. The document now does'n include the image xref object.

 

why don't you purge it?

 

Moshe

 

0 Likes
Message 3 of 22

pendean
Community Legend
Community Legend
0 Likes
Message 4 of 22

GeryKnee
Advocate
Advocate

Because purge all doesn't purge it.

0 Likes
Message 5 of 22

Moshe-A
Mentor
Mentor

@GeryKnee ,

 

post a sample dwg

 

 

0 Likes
Message 6 of 22

Moshe-A
Mentor
Mentor

@GeryKnee ,

 

I think now got you and i read your previous thread also >> here << 

 

Raster images are similar to xrefs. when you attach an image, AutoCAD create a record in AcDbDictionary section for that image and than add an image reference to model space (or paper space if you are in layout). the same happens with xrefs. say you have a dwg file and you xattach it in - ok? AutoCAD create a record in the blocks table and than add a block reference in model space known as insert - are you agree?! 

in order to remove an xref you must purge it.  the same goes with raster images. if you only delete them (by erase command) of course they are vanished form your drawing but they are still exist in AcDbDictionary section and the only way to remove it is purge.

 

so to summarize:-

if you want to remove a raster image, use purge directly (skipping erase) but if that image has multiple reference and you want to remove one (or some),  you would use erase.

 

does that make sense?

 

Moshe

 

 

 

 

 

 

  

0 Likes
Message 7 of 22

GeryKnee
Advocate
Advocate

I'm afraid, this is not solution.

I need a lisp code wich can purge all unused raster images, as happens for example to blocks (<<purge blocks>> removes blocks not referenced someware in a drawing).

my autocad platform is 2006 and purge doesn't work with images.

Newer versions of autocad maybe support this , but i'm too old to change the way i work.

Maybe lisp can do it.

Or maybe not.

Thanks,

Gery.

0 Likes
Message 8 of 22

Moshe-A
Mentor
Mentor

R2006 works on XP platform - Are you still working on XP/32 or win7/32?

 

post a sample dwg, please

 

 

0 Likes
Message 9 of 22

Moshe-A
Mentor
Mentor

@GeryKnee ,

 

check this PUIMG (Purge all Images) command. i test it on R2006 (i'm still keeping it in my Museum) and it works even dxfout it...and images are gone 😀

 

enjoy

Moshe

 

 

(defun c:puimg ()
 (vlax-for AcDbObject (vla-item
			(vla-get-dictionaries
			  (vla-get-activedocument (vlax-get-acad-object))
			)
		       "ACAD_IMAGE_DICT")
  (vla-delete AcDbObject)
  (vlax-release-object AcDbObject)
 )

 (princ) 
)

 

 

 

Message 10 of 22

Moshe-A
Mentor
Mentor

here is a more complete  solution

 

purge-unreferenced-images  

0 Likes
Message 11 of 22

GeryKnee
Advocate
Advocate

Yes,

That's solution.

Thank you very mach Moshe-A

Regards,

Gery

0 Likes
Message 12 of 22

GeryKnee
Advocate
Advocate

dear Moshe-A

Now I see that this code deletes all images from the document.

So execudung the code, you loose any image assigned.

So it is non working as "purge all UNUSED IMAGES" but "Delete all images of the document"

 

My Op system is Windows 7

 

Thanks,

Gery

0 Likes
Message 13 of 22

GeryKnee
Advocate
Advocate

Hello Moshe-A

Would you please how suld i call this code from command Line??

Thanks,

Ger.

0 Likes
Message 14 of 22

trevor.bird.au
Advocate
Advocate
Accepted solution

Hi Gery,

 

Please try the following program:

;;  PurgeImages.lsp by Trevor Bird
;;
;;  2021-02-20

;;------------------------------------------------------------------------------
(defun c:purgeimages
  (
    /

    ACAD_IMAGE_DICT__dxf
    ACAD_IMAGE_DICT__ename
    ACAD_REACTORS__dxf
    assoc_330

    count_imagedef
    count_imageref
    count_purged

    dps_3
    dps_330

    entity_dxf
    entity_ename
    entity_type

    imagedef_dxf
    imagedef_ename
    ImageFile
    imageref_dxf
    imageref_ename

    list_ImageNames
  )
  (setq count_purged  0)

  (cond
    (  (not (setq ACAD_IMAGE_DICT__dxf    (dictsearch (namedobjdict) "ACAD_IMAGE_DICT"))))
    (  (not (setq ACAD_IMAGE_DICT__ename  (cdr (assoc -1 ACAD_IMAGE_DICT__dxf)))))

      ;;  dps_3 = xrecord names = image names
    (  (not (setq dps_3  (vl-remove-if-not '(lambda ( _dp ) (= (car _dp) 3)) ACAD_IMAGE_DICT__dxf))))

      ;;  List of xrecord names = list of image Names
    (  (not (setq list_ImageNames  (mapcar 'cdr dps_3))))

    (list_ImageNames
      (foreach fe__ImageName list_ImageNames
        (setq imagedef_dxf    (dictsearch ACAD_IMAGE_DICT__ename fe__ImageName)
              imagedef_ename  (cdr (assoc -1 imagedef_dxf))
              ImageFile       (cdr (assoc 1 imagedef_dxf))
        );setq

        (cond
          (  (not (setq ACAD_REACTORS__dxf  (member  '(102 . "{ACAD_REACTORS") imagedef_dxf))))
          (  (not
                (setq ACAD_REACTORS__dxf  (reverse (member '(102 . "}") (reverse ACAD_REACTORS__dxf)))
                      dps_330             (vl-remove-if-not '(lambda ( _dp ) (= (car _dp) 330)) ACAD_REACTORS__dxf)
                );setq
            );not
          );

          (dps_330
            (setq count_imagedef  0
                  count_imageref  0
            );setq

            (foreach fe__dp dps_330
              (setq entity_ename  (cdr fe__dp)
                    entity_dxf    (entget entity_ename)
                    entity_type   (cdr (assoc 0 entity_dxf))
              );setq

              (cond
                (  (not (= entity_type "IMAGEDEF_REACTOR")))

                (  (not (setq count_imagedef  (1+ count_imagedef))))

                  ;;  330 - Object ID for associated image object (image reference)
                (  (not (setq assoc_330  (assoc 330 entity_dxf))))

                (assoc_330
                  (setq imageref_ename  (cdr assoc_330)
                        imageref_dxf    (entget imageref_ename)
                  );setq

                  (cond
                    (  (not imageref_dxf)
                      ;;  Image reference was deleted.
                    );(not imageref_dxf)

                    (imageref_dxf
                      (setq count_imageref  (1+ count_imageref))
                    );imageref_dxf
                  );cond
                );assoc_330
              );cond
            );fe__dp


            (if (zerop count_imageref)
              (progn
                ;;  Delete image definition xrecord.
                (setq count_purged  (1+ count_purged))
                (entdel imagedef_ename)
                (dictremove ACAD_IMAGE_DICT__ename fe__ImageName)

                (princ "\nDeleting image ")
                (prin1 fe__ImageName)
                (princ ".")
              );progn
            );if
          );dps_330
        );cond`
      );fe__ImageName
    );list_ImageNames
  );cond


  (cond
    (  (not (zerop count_purged))
      (princ "\n")
      (prin1 count_purged)

      (if (> count_purged 1)
        (princ " images ")
        (princ " image ")
      );if

      (princ "deleted.")
    );(not (zerop count_purged))

    (  (zerop count_purged)
      (princ "\nNo unreferenced images found.")
    );(zerop count_purged)
  );cond


  (princ)
);c:purgeimages


;;----------------------------------------------------------------------------------------
(princ "\nPurgeImages loaded. Start command with PURGEIMAGES.")
(princ)

PurgeImages.gif

Regards,

Trevor

Message 15 of 22

Moshe-A
Mentor
Mentor

@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

 

Message 16 of 22

Moshe-A
Mentor
Mentor
Accepted solution

@GeryKnee 

 

fixed a bug + fine tuning 😀

 

Moshe

 

Message 17 of 22

GeryKnee
Advocate
Advocate

Yes Moshe-A

That's perfect

After all that's exactly the solution

Thank you very match

Gery

0 Likes
Message 18 of 22

GeryKnee
Advocate
Advocate

The code works perfectly

Thank you very match,

Sinceres,

Gery

0 Likes
Message 19 of 22

Lott99
Enthusiast
Enthusiast

Would this be easily modified to work on images that are "Not Found" as well as "Unreferenced"?

0 Likes
Message 20 of 22

trevor.bird.au
Advocate
Advocate

Hi Lott99,

 

I've updated this program to delete image references and purge the image if the image file cannot be found.

 

 

;;  PurgeImages.lsp by Trevor Bird
;;
;;  2021-02-24

;;------------------------------------------------------------------------------
(defun c:purgeimages
  (
    /

    ACAD_IMAGE_DICT__dxf
    ACAD_IMAGE_DICT__ename
    ACAD_REACTORS__dxf
    assoc_330

    count_imagedef
    count_imageref
    count_purged

    dps_3
    dps_330

    entity_dxf
    entity_ename
    entity_type

    imagedef_dxf
    imagedef_ename
    ImageFile
    ImageFile_fqn
    imageref_dxf
    imageref_ename

    list_ImageNames

    sv_dwgprefix
  )
  (setq count_purged  0)

  (cond
    ( (not (setq ACAD_IMAGE_DICT__dxf    (dictsearch (namedobjdict) "ACAD_IMAGE_DICT"))))
    ( (not (setq ACAD_IMAGE_DICT__ename  (cdr (assoc -1 ACAD_IMAGE_DICT__dxf)))))

      ;;  dps_3 = xrecord names = image names
    ( (not (setq dps_3  (vl-remove-if-not '(lambda ( _dp ) (= (car _dp) 3)) ACAD_IMAGE_DICT__dxf))))

      ;;  List of xrecord names = list of image Names
    ( (not (setq list_ImageNames  (mapcar 'cdr dps_3))))

    (list_ImageNames
      (setq sv_dwgprefix (getvar 'DWGPREFIX))

      (foreach fe__ImageName  list_ImageNames
        (setq imagedef_dxf    (dictsearch ACAD_IMAGE_DICT__ename fe__ImageName)
              imagedef_ename  (cdr (assoc -1 imagedef_dxf))
              ImageFile       (cdr (assoc 1 imagedef_dxf))
        );setq

        (cond
          ( (setq ImageFile_fqn (findfile ImageFile)))
          ( (setq ImageFile_fqn (findfile (strcat sv_dwgprefix ImageFile))))
        );cond

        (cond
          ( (not (setq ACAD_REACTORS__dxf  (member  '(102 . "{ACAD_REACTORS") imagedef_dxf))))
          ( (not
                (setq ACAD_REACTORS__dxf  (reverse (member '(102 . "}") (reverse ACAD_REACTORS__dxf)))
                      dps_330             (vl-remove-if-not '(lambda ( _dp ) (= (car _dp) 330)) ACAD_REACTORS__dxf)
                );setq
            );not
          );

          (dps_330
            (setq count_imagedef  0
                  count_imageref  0
            );setq

            (foreach fe__dp dps_330
              (setq entity_ename  (cdr fe__dp)
                    entity_dxf    (entget entity_ename)
                    entity_type   (cdr (assoc 0 entity_dxf))
              );setq

              (cond
                ( (not (= entity_type "IMAGEDEF_REACTOR")))

                ( (not (setq count_imagedef  (1+ count_imagedef))))

                  ;;  330 - Object ID for associated image object (image reference)
                ( (not (setq assoc_330  (assoc 330 entity_dxf))))

                (assoc_330
                  (setq imageref_ename  (cdr assoc_330)
                        imageref_dxf    (entget imageref_ename)
                  );setq

                  (cond
                    ( (not imageref_dxf)
                      ;;  Image reference was deleted.
                    );(not imageref_dxf)

                    ( (not ImageFile_fqn)
                      ;;  Image references exist but image file cannot be found.
                      (entdel imagedef_ename)
                    );(not ImageFile_fqn)

                    (imageref_dxf
                      (setq count_imageref  (1+ count_imageref))
                    );imageref_dxf
                  );cond
                );assoc_330
              );cond
            );fe__dp


            (if (zerop count_imageref)
              (progn
                ;;  Delete image definition xrecord.
                (setq count_purged  (1+ count_purged))
                (entdel imagedef_ename)
                (dictremove ACAD_IMAGE_DICT__ename fe__ImageName)

                (princ "\nDeleting image ")
                (prin1 fe__ImageName)
                (princ ".")
              );progn
            );if
          );dps_330
        );cond
      );fe__ImageName
    );list_ImageNames
  );cond

  (cond
    ( (not (zerop count_purged))
      (princ "\n")
      (prin1 count_purged)

      (if (> count_purged 1)
        (princ " images ")
        (princ " image ")
      );if

      (princ "deleted.")
    );(not (zerop count_purged))

    ( (zerop count_purged)
      (princ "\nNo unreferenced images found.")
    );(zerop count_purged)
  );cond

  (princ)
);c:purgeimages


;;----------------------------------------------------------------------------------------
(princ "\nPurgeImages loaded. Start command with PURGEIMAGES.")
(princ)

 

 

Regards,

Trevor Bird

0 Likes