Need help modifying this lisp code to automatically know how many pages are in a pdf and size them appropriately when inserted

Need help modifying this lisp code to automatically know how many pages are in a pdf and size them appropriately when inserted

fabi_rm94
Enthusiast Enthusiast
1,684 Views
22 Replies
Message 1 of 23

Need help modifying this lisp code to automatically know how many pages are in a pdf and size them appropriately when inserted

fabi_rm94
Enthusiast
Enthusiast

Hello everyone,

 

Have a question about the best way to modify this code to automatically know how many pages are in a pdf and size them appropriately within the paper space page layout. The code currently ask in its second step how many pages the user wants to bring in from the selected pdf. I want to bypass that 2nd step and have the code be able to know how many pages are in the pdf document and automatically place them and scale them on the page. 

 

I want to size the pdf pages/documents as follows:

     -  If the file has 1 sheet and is in portrait orientation, then the insertion location should be "4.5, 1.375" and scale of "0.75".

     - If the file has 1 sheet and is in landscape orientation, then the insertion location should be "0.75, 1.375" and be a scale of "0.75".

     - If the file has 2 sheets, then the insertion locations should be "0.75, 1.375" for the 1st page and "7.5, 1.375" for the 2nd page, both with a scale of "0.75".

     - If the file has 3 sheets, then the insertion locations should be "0.75, 3.025" for the 1st page, "5.23, 3.025" for the 2nd page, and "9.71, 3.025" for the 3rd page, all with a scale of "0.48".

     - If the file has 4 sheets, then the insertion locations should be "0.37629, 3.3" for the 1st page, "3.85812, 3.3" for the 2nd page, "7.33995, 3.3" for the 3rd page, and "10.8218, 3.3" for the 4th page.

 

 

BUPSUP(defun c:BUPSUP ( / )
	(c:BUPSUP)
)

(defun c:BUPSUP 
	( 
		/
		; Functions
			MN:ListBox _PDFPageCount findEmptySlot IncrementSheet ClearSheet
		;Variables
			dir lst mfr specs inspts pt scl pages page_lst cur_layout
	)
	
	(cb:writetotext "networks" "SPCI")
	
	(vl-load-com)
	
	(defun MN:ListBox ( title lst bit / *error* dch des tmp res )

		(defun *error* ( msg )
			(if (< 0 dch)
				(unload_dialog dch)
			)
			(if (= 'file (type des))
				(close des)
			)
			(if (and (= 'str (type tmp)) (setq tmp (findfile tmp)))
				(vl-file-delete tmp)
			)
			(if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
				(princ (strcat "\nError: " msg))
			)
			(princ)
		)

		(cond
			(
				(not
					(and
						(setq tmp (vl-filename-mktemp nil nil ".dcl"))
						(setq des (open tmp "w"))
						(write-line
							(strcat
								"listbox : dialog
								{
									label = \"" title "\";
									spacer;
									: list_box
									{
										key = \"list\";
										multiple_select = " (if (null bit) "false" "true")";
									}
									width = 50;
									fixed_width = true;
									spacer;
									ok_cancel;
								}"
							)
							des
						)
						(not (close des))
						(< 0 (setq dch (load_dialog tmp)))
						(new_dialog "listbox" dch)
					)
				)
				(prompt "\nError loading list box.")
			)
			( 1
				(start_list "list")
				(foreach item lst (add_list item))
				(end_list)
				(setq res (set_tile "list" "0"))
				(action_tile "list" "(setq res $value)")
				(setq res
					(if (= 1 (start_dialog))
						(mapcar '(lambda ( x ) (nth x lst)) (read (strcat "(" res ")")))
					)
				)
			)
		)
		(if (< 0 dch)
			(setq dch (unload_dialog dch))
		)
		(if (and (= 'str (type tmp)) (setq tmp (findfile tmp)))
			(vl-file-delete tmp)
		)
		(if (not (null res))
			res
			nil
		)
	)
	
	(defun _PDFPageCount ( filename / fob fso mat reg res str )
		(if
			(and
				(setq filename (findfile filename))
				(eq ".PDF" (strcase (vl-filename-extension filename)))
			)
			(vl-catch-all-apply
				(function
					(lambda ( / _ReadAsTextFile _CountPage )
						(defun _ReadAsTextFile ( fso fn / fob str res )
							(setq
								fob (vlax-invoke fso 'getfile fn)
								str (vlax-invoke fso 'opentextfile fn 1 0)
								res (vlax-invoke str 'read (vlax-get fob 'size))
							)
							(vlax-invoke str 'close)
							(vlax-release-object str)
							(vlax-release-object fob)
							res
						)
						(defun _CountPage ( rgx str / mat pag )
							(vlax-put-property rgx 'pattern "/Type\\s*/Page[^s]")
							(vlax-put-property rgx 'ignorecase actrue)
							(vlax-put-property rgx 'global actrue)
							(setq
								mat (vlax-invoke rgx 'execute str)
								pag (vlax-get mat 'count)
							)
							(vlax-release-object mat)
							(if (zerop pag) 1 pag)             
						)
						(setq
							fso (vlax-create-object "Scripting.FileSystemObject")
							reg (vlax-create-object "VBScript.RegExp")
							str (_ReadAsTextFile fso filename)
							res (_CountPage reg str)
						)
					)
				)
			)
		)
		(foreach obj (list str fob mat fso reg)
			(vl-catch-all-apply 'vlax-release-object (list obj))
		)
		res
	)
	;; Translation by Lee Mac of the VBScript code by Chanh Ong
	;; found at http://docs.ongetc.com/?q=content/pdf-pages-counting-using-vb-script
	;;
	;; Call with fully qualified filename of PDF file:
	;; (_PDFPageCount "C:\\Folder\\Filename.pdf")
	;;
	;; Returns integer describing number of pages in specified PDF file
	
	
	(defun findEmptySlot ( lst / i ent nums )
		;; CONVERT LST "1.009,2.869,3.14" -> (LIST 1.009 2.869 3.14)
		(setq i 0)
		(cond
			((eq 'STR (type (nth i lst)))
				(setq nums (mapcar '(lambda (x y) (cons (atof (substr x 1 (vl-string-search "," x))) (atof (substr y (+ (vl-string-search "," y) 2))))) lst lst))
				(while (and (setq ent (nentselp "" (list (car (nth i nums)) (cdr (nth i nums))))) (/= i (1- (length lst))))
					;(vl-remove-if-not '(lambda (x) (wcmatch x "*R-*")) (layoutlist))
					(setq i (1+ i))
				)
				(if (null ent)
					(nth i lst)
				)
			)
		)
	)
	
	
	(defun ClearSheet ( ss / ind ent )
		(repeat (setq ind (sslength ss))
			(setq
				ind (1- ind)
				ent (ssname ss ind)
			)
			(entdel ent)
		)
		(princ)
	)
	; [SS] SELECTION SET 
	; CLEARS OUT ALL ENTITIES PASSED AS SELECTION SET [SS]
	
	
	(defun IncrementSheet ( sht / sht+ )
		(setq sht+
			(strcat
				(substr sht 1 (1+ (vl-string-search "-" sht)))
				(rtos (1+ (atoi (substr sht (+ (vl-string-search "-" sht) 2)))) 2 0)
			)
		)
	)
	
	
	;;; MAIN ;;;
	(setq dir "C:\\_Vault\\ATC\\DAS\\_DAS Library\\BUP Supplementals")
	(if (not (vl-file-directory-p dir))
		(princ (strcat "Directory: " dir "\nNot found.\nPlease download/'GET' this location from Vault."))
		(progn
			(setq lst (vl-remove-if '(lambda (x) (and (member x (list "." ".." "_V")))) (vl-directory-files dir nil -1)))
			(if
				(and
					(setq mfr (car (MN:ListBox "Select Generator Manufacturer:" lst nil)))
					(setq specs (MN:ListBox "Select Generator Spec Sheet(s):" (vl-directory-files (strcat dir "\\" mfr) "*.pdf*" 1) 1))
				)
				(progn
					(setq
						inspts (list
									"0.60475,1.38142"
									"7.42514,1.38142"
								)
						scl "0.77272727"
					)
					(if (vl-catch-all-error-p (vl-catch-all-apply 'setvar (list "CTAB" "R-601")))
						(princ "\nError.\nLayout tab 'R-601' does not exist.")
						(foreach spec specs
							;(command-s "PDFATTACH" (strcat dir "\\" mfr "\\" spec))
							(setq pages (_PDFPageCount (strcat dir "\\" mfr "\\" spec)))
							(setq page_lst nil)
							(repeat pages
								(setq page_lst (cons (rtos pages 2 0) page_lst))
								(setq pages (1- pages))
							)
							
							(setq page_lst (MN:Listbox (strcat "Select " spec " sheet(s):") page_lst 1))
							
							(foreach p page_lst
								(setq cur_layout (getvar "CTAB"))
								(while
									(not
										(cond
											((setq pt (findEmptySlot inspts))
												; insertion point or nil
												T
											)
											((vl-catch-all-error-p (vl-catch-all-apply 'setvar (list "CTAB" (setq cur_layout (IncrementSheet (getvar "CTAB"))))))
												; T or nil
												(command "_.LAYOUT" "C" (getvar "CTAB") cur_layout)
												(setvar "CTAB" cur_layout)
												(ClearSheet (ssget "C" '(0.60475 9.88142) '(13.9933 1.38142)))
												(setq pt (findEmptySlot inspts))
											)
										)
									)
								)
								(command "-PDFATTACH" (strcat dir "\\" mfr "\\" spec) p pt scl "0.0" nil)
								(setq pt nil)
							)
						)
					)
				)
				(princ "\nFunction canceled")
			)
		)
	)
	(princ)
)


;;;---------------------------------------------------------------------------------------------
; ...
; ...
;;;---------------------------------------------------------------------------------------------

 

 

I've attached the lisp code and the template to help with context. Feel free to modify the setq dir "C:\\_Vault\\ATC\\DAS\\_DAS Library\\BUP Supplementals" to any location with whatever pdfs you want to use to test out the code. 

 

Appreciate any help. 

0 Likes
Accepted solutions (2)
1,685 Views
22 Replies
Replies (22)
Message 2 of 23

fabi_rm94
Enthusiast
Enthusiast

Bump!

0 Likes
Message 3 of 23

paullimapa
Mentor
Mentor

I modified your code to accommodate for multiple page attachment into a single layout.

Try this with your pdfs. They should work if they're Letter size.

Since you only provided an option for a single page landscape pdf, the code currently only accommodates for this with the remainder designed to work for multiple page portrait.

Also you did not include a scale factor for 4 pages so I just used 0.4 which works.

If you have another factor, then just replace 0.4 by searching for this line:

(setq scl 0.4)
 

Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 4 of 23

Sea-Haven
Mentor
Mentor

Re scaling, attach pdf at a scale of 1. You can get and change the properties of a pdf and work out a new scale so it fits your layout. You need to check wether height or width controls the scale.

 

 

   Height = 0.2794
   Position = (0.0 0.0 0.0)
   Rotation = 0.0
   ScaleFactor = 0.0254
   Width = 0.4318

 

 

0 Likes
Message 5 of 23

fabi_rm94
Enthusiast
Enthusiast

This worked really well! Is there any way you could also help me figure out this last addition to the same code?

 

I want to add a code section that brings in a detail title block (the block would already exist in the drawing, so copying it and pasting it would not be a problem if necessary) and places it on any page where I'm inserting a pdf xref. The trick is that I want the value of the title block to change to the name of the pdf Im selecting to open in that specific page/layout tab. Is there any way you can think to do that?

 

Example: I run the latest version of the code you've attached in your response, and I select to insert the pdf called "large gallon tank", I'd then want the code to insert a block called "DETL_TITLE" at "6.0, 0.75", scale "1" and have the name attribute of that block change to "large gallon tank". 

fabi_rm94_0-1690406952642.png

 

You'd be a wizard if you could help me out with this last update!

 

 

0 Likes
Message 6 of 23

paullimapa
Mentor
Mentor

This request is so much easier than the original.

I've updated the code to include at the end the steps to change the detail title block View Name to match with the pdf's file name. Download the latest attached lisp file & give it a try.

; insert detail title block and fill title with pdf name        
              (setq blkname "DETL_TITLE" tagname "VIEWNAME")
              (if(tblsearch "BLOCK" blkname) ; if block exists in current dwg
                 (progn
                  (if (not(setq ss (ssget"_X"(list (cons 0 "INSERT") (cons 2 blkname) (cons 66 1) (cons 410 (getvar "ctab")))))) ; chk if already inserted in current layout
                   (vl-cmdf "_.Insert" blkname "6.0,0.75" 1 1 0)
                   ; make sure existing blk is placed in correct location
                   (vla-put-insertionpoint (vlax-ename->vla-object (ssname ss 0)) (vlax-3D-point (list 6.0 0.75 0)))
                  )
                  (if (setq ss (ssget"_X"(list (cons 0 "INSERT") (cons 2 blkname) (cons 66 1) (cons 410 (getvar "ctab"))))) ; select blk
                   (foreach attribute (vlax-invoke (vlax-ename->vla-object (ssname ss 0)) 'getattributes) ; cycle through all attributes
                    (setq attribute_tag (strcase (vla-get-tagString attribute)))
                    (if (wcmatch attribute_tag tagname) ; when found matching tag
                     (vla-put-textString attribute spec) ; put pdf name as string value
                    ) ; if
                   ) ; foreach
                  ) ; if
                 ) ; progn
              ) ; if   

 


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 7 of 23

fabi_rm94
Enthusiast
Enthusiast

Do you have any idea why the lisp tends to work the first time you try it but afterwards it will just create a copy of the ctab and not bring in the pdfs? It's very fragile at the moment and I don't know why. Im trying to troubleshoot it but nothing is helping

fabi_rm94_0-1690474094844.png

 

0 Likes
Message 8 of 23

paullimapa
Mentor
Mentor

That is odd. Not sure why that’s the case. 


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 9 of 23

paullimapa
Mentor
Mentor

Reviewing your screen shot looks like you are using two separate commands. One is called BUPSUP which is the code I worked on and the other is BUPSUPPLEM which is another code I’m not aware of. Perhaps they’re conflicting?


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 10 of 23

fabi_rm94
Enthusiast
Enthusiast

see comment below

0 Likes
Message 11 of 23

fabi_rm94
Enthusiast
Enthusiast

I've been troubleshooting so I've been trying different versions of the lisp routine so I can figure out what works without having to undo all the time. 

 

Its currently working so Im just trying to go with what I have. The last request I have is that I'm able to delete the ".pdf" part of the view name that's coming in with the pdf name, delete the scale, and make the leading line under the title name as long as the name (if thats not possible setting to a distance of 3" would be ok)

 

Example: 

fabi_rm94_0-1690480215479.png

 

0 Likes
Message 12 of 23

fabi_rm94
Enthusiast
Enthusiast

I figured out when it doesn't work. It doesn't work when R-601 is the last page in the template. When I run it then, R-602 is created and the lisp stops. If R-602 already exists, then it runs fine. Ideally I would want it to create R-602 and then keep going with the rest of the lisp but that's not what seems to be happening. 

0 Likes
Message 13 of 23

paullimapa
Mentor
Mentor

Ok, I think I resolved all the issues. The latest code should do the following:

; Copy R-601 layout as template & move to last position in the series
; Attach multiple page pdfs into single layout
; Insert Detail Title callout, label to match with PDF name and extend line
Give it a try and let me know if there are any more issues.

Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 14 of 23

fabi_rm94
Enthusiast
Enthusiast

The only thing that still doesnt work is the R-601 page part, and I think I need to clarify myself. BEFORE I use the lisp, the last page will be R-601 on the template. I need the lisp to run the command and place the PDFs chosen STARTING on R-601. 

 

Currently, the lisp is creating a copy of R-601, changing its name to R-602, and THEN placing the selected pdfs on R-602. I need that process to start on the very first page (R-601), and then, if needed, create further copies of R pages that count up (R-602, R-603, R-604, etc). I do not need the LISP to move R-601 to the end of the created R pages.

 

I do believe the fix is a very quick and easy one, I just can't quite figure out how to fix it or what to change that part of the code to. 

 

Thanks so much! 

0 Likes
Message 15 of 23

paullimapa
Mentor
Mentor
Accepted solution

Ok, the modify lisp should start attaching pdfs on layout R-601...give this a try.


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 16 of 23

fabi_rm94
Enthusiast
Enthusiast

I just wanted to thank you for all your help.

 

I've made a few changes to the lisp for different functions that are not related to this, and along the way started wondering what the most efficient thing to add to the code you've uploaded to cut out the numbers from the title block if a pdf name with a number is chosen to bring in its xref. 

 

fabi_rm94_0-1692423571348.png

 

0 Likes
Message 17 of 23

paullimapa
Mentor
Mentor

Well, this is how I would tackle this.

Towards the end of the code this is the line that places the pdf name into the attribute title:

(vla-put-textString attribute (vl-filename-base spec)) ; put pdf name with no extension as string value

Before this happens you can examine the pdf name to see if it starts with any numbers. 

; For example: "285 TANK SPEC.pdf"
(setq pdfname (vl-filename-base spec)) ; get pdf name with no extension
; returns: "285 TANK SPEC"
(setq namechk(atoi pdfname)) ; if name does not begin with # then returns 0 otherwise in this case returns: 285
(if (not (zerop namechk)) ; do the following when name begins with #
  (progn
   (setq namelength (strlen (itoa namechk))) ; find out numbers have how many characters in this case returns: 3
   (substr pdfname (+ namelength 2)) ; assumes there's a space following #s gets rest of name in this case returns: TANK SPEC 
  )
)
(vla-put-textString attribute pdfname) ; put pdf name as string value

Now this does not check if the filename just has numbers and no alphabets

 


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 18 of 23

fabi_rm94
Enthusiast
Enthusiast

I tried putting the above code in a couple of different places before the "vla-put-textstring attribute" part and it never worked. Not sure what's going on. Attached is the latest version of the code I have. If you could help me figure this last bit out, I'd be eternally grateful

0 Likes
Message 19 of 23

paullimapa
Mentor
Mentor

I made the changes basically in this section as I mentioned.

I did not test the entire routine. I'll leave that up to you.

paullimapa_0-1692911437665.png

 


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 20 of 23

fabi_rm94
Enthusiast
Enthusiast

Unfortunately, the detail title block is still coming in with the 285 ahead of it. I've tried various locations for that snippet of the code and general troubleshooting for it and nothing has worked. Is there something missing in that part of the code? 

0 Likes