Set resolution when exporting artboards to PNG using script - scripting

Sorry that this is so similar to a recent post but I can't find the solution anywhere. I have created a simple script that loops through each artboard in an open illustrator document and exports it as a separate PNG file. All is working well except that I want to set the resolution to 150 dpi and not the default 72 dpi, for production reasons. This is an option that you can set when exporting manually to PNG but I don't seem to be able to set it in the PNG options in the code, although the script runs without errors it ignores the resolution setting. Could someone let me know how to do this, many thanks. Code as follows:
var doc = app.activeDocument;;//Gets the active document
var fileName = doc.name.slice(0, 9);//Gets the G Number
var numArtboards = doc.artboards.length;//returns the number of artboards in the document
var filePath = (app.activeDocument.fullName.parent.fsName).toString().replace(/\\/g, '/');
var options = new ExportOptionsPNG24();
for (var i = 0; i < numArtboards; i++ ) {
doc.artboards.setActiveArtboardIndex( i );
options.artBoardClipping = true;
options.matte = false;
options.horizontalScale = 100;
options.verticalScale = 100;
options.transparency = true;
var artboardName = doc.artboards[i].name;
//$.writeln("artboardName= ", artboardName);
var destFile = new File(filePath + "/" + fileName + " " + artboardName + ".png");
//$.writeln("destFile= ",destFile);
doc.exportFile(destFile,ExportType.PNG24,options);
}

After doing some digging I've found that if you use imageCapture you can set the resolutuion. So new script below. thanks to CarlosCanto for providing this link via the Adobe Forum https://forums.adobe.com/message/9075307#9075307
var doc = app.activeDocument;;//Gets the active document
var fileName = doc.name.slice(0, 9);//Gets the G Number
var numArtboards = doc.artboards.length;//returns the number of artboards in the document
var filePath = (app.activeDocument.fullName.parent.fsName).toString().replace(/\\/g, '/');
var options = new ImageCaptureOptions();
for (var i = 0; i < numArtboards; i++) {
doc.artboards.setActiveArtboardIndex(i);
var activeAB = doc.artboards[doc.artboards.getActiveArtboardIndex()];
options.artBoardClipping = true;
options.resolution = 150;
options.antiAliasing = true;
options.matte = false;
options.horizontalScale = 100;
options.verticalScale = 100;
options.transparency = true;
var artboardName = doc.artboards[i].name;
var destFile = new File(filePath + "/" + fileName + " " + artboardName + ".png");
doc.imageCapture(destFile, activeAB.artboardRect, options);
}

Related

in Gscript, how to convert sheets to multiple pdfs without timeout

I'm trying to setup a gradebook, I would like to loop through the list of students in a sheet that has various vlookups to create an individual mark sheet. I would then like to make a pdf for each of the students. I keep hitting a timeout on the server requests after about 6 students. An error message reports "returned code 429."
I thought I had it working but it would just create a pdf for each student with the first student's information and name. I've tried various code snippets found around the internet but those also time out due to the number of requests.
function PrintReport() {
SpreadsheetApp.getActiveSpreadsheet().toast('Writing the reports.','Printing Reports');
var email = Session.getActiveUser().getEmail();
var TodayDate = new Date();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ClassName = ss.getName()
var url = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());
var StudentList = ss.getSheetByName('Mark Sheet');
var StudentCount = StudentList.getRange("A2").getValue();
var SLData = StudentList.getRange(7,1,StudentCount).getValues();
var ReportSheet = ss.getSheetByName('Student Report');
var url_ext = 'exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
+ '&size=letter' // paper size legal / letter / A4
+ '&portrait=false' // orientation, false for landscape
+ '&fitw=true&source=labnol' // fit to page width, false for actual size
+ '&sheetnames=False&printtitle=True' // hide optional headers and footers
+ '&pagenumbers=false&gridlines=false' // hide page numbers and gridlines
+ '&fzr=false' // do not repeat row headers (frozen rows) on each page
+ '&gid='; // the sheet's Id
var token = ScriptApp.getOAuthToken();
var blobs = [];
var sheetID = ss.getSheetByName('Student Report').getSheetId();
var url_base = ss.getUrl().replace(/edit/,'');
for (var i = 0; i < StudentCount; i++){
ReportSheet.setActiveSelection("B1").setValue(SLData[i][0].toString());
SpreadsheetApp.flush();
var response = UrlFetchApp.fetch(url + url_ext + sheetID, {
headers: {'Authorization': 'Bearer ' + token
}
});
//convert the response to a blob and store in our array
blobs[i] = response.getBlob().setName(SLData[i][0] + '.pdf');
}
ReportSheet.setActiveSelection("B1").setValue(SLData[0][0]);
//create new blob that is a zip file containing our blob array
var zipBlob = Utilities.zip(blobs).setName(ClassName+': Student Reports'+'.zip');
var subject = ClassName+ ": Individual Reports";
var body = "How to print multiple files: Just select all the items you wish to print in Finder and tap Command-P (or choose File>Print). If your system can print those items, it will.";
// If allowed to send emails, send the email with the PDF attachment
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail(email, subject, body, {
htmlBody: body,
attachments:[zipBlob]
});
SpreadsheetApp.getActiveSpreadsheet().toast('Reports are all done, please check you email.','Reports',5);
}
It is supposed to create a zipped file of pdfs with the student's names. When the zip is downloaded and extracted, the pdfs contain the mark break down for each student.
If I move the "response" code outside the loop, it produces multiple PDFs with just one student's data.
UPDATE
Modified to the code below but now it makes a pdf for each student but everyone has the last student's information (mark and name).
function PrintReport() {
SpreadsheetApp.getActiveSpreadsheet().toast('Writing the reports.','Printing Reports');
var email = Session.getActiveUser().getEmail();
var TodayDate = new Date();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ClassName = ss.getName();
var StudentList = ss.getSheetByName('Mark Sheet');
var StudentCount = StudentList.getRange("A2").getValue();
var SLData = StudentList.getRange(7,1,StudentCount).getValues();
var ReportSheet = ss.getSheetByName('Student Report');
var sheetID = ss.getSheetByName('Student Report').getSheetId();
var blobs = [];
hideAllSheetsExcept('Student Report');
for (var i = 0; i < StudentCount; i++){
ReportSheet.setActiveSelection("B1").setValue(SLData[i][0].toString());
SpreadsheetApp.flush();
//convert the response to a blob and store in array
blobs.push(ss.getBlob().getAs('application/pdf').setName(SLData[i][0] + '.pdf'));
//creates a pdf of the last student's information for everyone!
}
ReportSheet.setActiveSelection("B1").setValue(SLData[0][0]);
//create new blob that is a zip file containing our blob array
var zipBlob = Utilities.zip(blobs).setName(ClassName+': Student Reports'+'.zip');
var subject = ClassName+ ": Individual Reports";
var body = "How to print multiple files: Just select all the items you wish to print in Finder and tap Command-P (or choose File>Print). If your system can print those items, it will.";
// If allowed to send emails, send the email with the PDF attachment
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail(email, subject, body, {
htmlBody: body,
attachments:[zipBlob]
});
SpreadsheetApp.getActiveSpreadsheet().toast('Reports are all done, please check you email.','Reports',5);
UnHideEverything();
}
I added a try catch in a while loop and a timeout. Works perfectly
So nest your response like this:
var theurl = 'https://docs.google.com/a/mydomain.org/spreadsheets/d/'
+ ssID
+ '/export?exportFormat=pdf&format=pdf'
+ '&size=A4'
+ '&portrait=true'
+ '&fitw=true'
+ '&top_margin=0.50'
+ '&bottom_margin=0.50'
+ '&left_margin=0.50'
+ '&right_margin=0.50'
+ '&sheetnames=false&printtitle=false'
+ '&pagenum=false'
+ '&gridlines=false'
+ '&fzr=FALSE'
+ '&gid='
+ GID;
var response
var done = false
while (!done){
try{
response = UrlFetchApp.fetch(theurl, params)
done = true
} catch (e) {
console.log(e)
done = false
Utilities.sleep(10000)
}
}

Replacing smart objects in bulk with Photoshop

Just facing this issue: I have a mockup in Photoshop with two smart-objects: Rectangle 14.psb and Place your logo.psb
I have 100+ images in png that should be applied to create mockups.
For this reason, I would like your help to create a script that:
Let me select the png file that I would like to use
Open the smart objects (Rectangle 14.psb and Place your logo.psb)
Re-Link the same png to the layers "place your logo" of both the smart objects.
Finally, the script should save the file as png with the same file name of the selected png file adding just _new after its name.
So far I have tried this code without any luck:
#target photoshop
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theName = myDocument.name.match(/(.*)\.[^\.]+$/)[1];
var thePath = myDocument.path;
var theLayer = myDocument.activeLayer;
// PSD Options;
psdOpts = new PhotoshopSaveOptions();
psdOpts.embedColorProfile = true;
psdOpts.alphaChannels = true;
psdOpts.layers = true;
psdOpts.spotColors = true;
// Check if layer is SmartObject;
if (theLayer.kind != "LayerKind.SMARTOBJECT") {
alert("selected layer is not a smart object")
} else {
// Select Files;
if ($.os.search(/windows/i) != -1) {
var theFiles = File.openDialog("please select files",
"*.psd;*.tif;*.jpg;*.png", true)
} else {
var theFiles = File.openDialog("please select files", getFiles,
true)
};
if (theFiles) {
for (var m = 0; m < theFiles.length; m++) {
// Replace SmartObject
theLayer = replaceContents(theFiles[m], theLayer);
var theNewName = theFiles[m].name.match(/(.*)\.[^\.]+$/)[1];
// Save JPG
myDocument.saveAs((new File(thePath + "/" + theName + "_" +
theNewName + ".psd")), psdOpts, true);
}
}
}
};
// Get PSDs, TIFs and JPGs from files
function getFiles(theFile) {
if (theFile.name.match(/\.(psd|png|jpg)$/i) != null ||
theFile.constructor.name == "Folder") {
return true
};
};
// Replace SmartObject Contents
function replaceContents(newFile, theSO) {
app.activeDocument.activeLayer = theSO;
// =======================================================
var idplacedLayerReplaceContents =
stringIDToTypeID("placedLayerReplaceContents");
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc3.putPath(idnull, new File(newFile));
var idPgNm = charIDToTypeID("PgNm");
desc3.putInteger(idPgNm, 1);
executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);
return app.activeDocument.activeLayer
};
The above code substitute the smart object but I would like just to re-link the layer withing the smartobject to a new image and save the file. Any help would be much appreciated!
Are you familiar with Scriptlistener? You can use it to get all the functions you need and then modify the output to run within your loop of 100 pngs, it should be straightforward.

Updating the google spreedsheet from MS SQL using Google Scripts

I'm trying to connect the MS SQL to a google spreadsheet using google app scripts. here is my app script code
function SQLdb() {
// Replace the variables in this block with real values.
// Read up to 1000 rows of data from the table and log them.
function readFromTable() {
var user = '{usename}';
var userPwd = '{password}';
var database = '{databasename}'
var connectionString = 'jdbc:sqlserver://server.database.windows.net:1433;databaseName='+database;
var conn = Jdbc.getConnection(connectionString , user, userPwd);
var start = new Date();
var stmt = conn.createStatement();
stmt.setMaxRows(1000);
var results = stmt.executeQuery('SELECT TOP 1000 * FROM dbo.dbo');
var numCols = results.getMetaData().getColumnCount();
while (results.next()) {
var rowString = '';
for (var col = 0; col < numCols; col++) {
rowString += results.getString(col + 1) + '\t';
}
Logger.log(rowString)
}
results.close();
stmt.close();
var end = new Date();
Logger.log('Time elapsed: %sms', end - start);
}
readFromTable();
}
Now when I look the log in Script Editor, I can see that this connection to the SQL database is working and the script is able to read all the table cell. But I couldn't able to get that data into the spreedsheet. I'm new to app scripts. So is there something that I'm missing here ?
Any help would be much appricated!
Here's how I do it. Change all the capitalised bits to the appropriate URL, database name, Google Spreadsheet ID, etc.
To this function pass the SQL query you want to execute on the MSSQL database and the name of the sheet within the Spreadsheet that you want to put the data into. This basically fills that named sheet with the query results including column names.
function getData(query, sheetName) {
//jdbc:sqlserver://localhost;user=MyUserName;password=*****;
var conn = Jdbc.getConnection("jdbc:sqlserver://URL;user=USERNAME;password=PASSWORD;databaseName=DBNAME");
var stmt = conn.createStatement();
stmt.setMaxRows(MAXROWS);
var rs = stmt.executeQuery(query);
Logger.log(rs);
var doc = SpreadsheetApp.openById("SPREADSHEETID");
var sheet = doc.getSheetByName(sheetName);
var results = [];
var cell = doc.getRange('a1');
var row = 0;
cols = rs.getMetaData();
colNames = [];
for (i = 1; i <= cols.getColumnCount(); i++ ) {
Logger.log(cols.getColumnName(i));
colNames.push(cols.getColumnName(i));
}
results.push(colNames);
var rowCount = 1;
while(rs.next()) {
curRow = rs.getMetaData();
rowData = [];
for (i = 1; i <= curRow.getColumnCount(); i++ ) {
rowData.push(rs.getString(i));
}
results.push(rowData);
rowCount++;
}
sheet.getRange(1, 1, MAXROWS, cols.getColumnCount()).clearContent();
sheet.getRange(1, 1, rowCount, cols.getColumnCount()).setValues(results);
Logger.log(results);
rs.close();
stmt.close();
conn.close();
}
Here is how i did it. I also made a JDBC connector tool for Mysql & MSSQL. You can adapt this tool from my GitHub Repo Here: Google Spreadsheet JDBC Connector
function readFromTable(queryType, queryDb, query, tab, startCell) {
// Replace the variables in this block with real values.
var address;
var user;
var userPwd ;
var dbUrl;
switch(queryType) {
case 'sqlserver':
address = '%YOUR SQL HOSTNAME%';
user = '%YOUR USE%';
userPwd = '%YOUR PW%';
dbUrl = 'jdbc:sqlserver://' + address + ':1433;databaseName=' + queryDb;
break;
case 'mysql':
address = '%YOUR MYSQL HOSTNAME%';
user = '%YOUR USER';
userPwd = '%YOUR PW%';
dbUrl = 'jdbc:mysql://'+address + '/' + queryDb;
break;
}
var conn = Jdbc.getConnection(dbUrl, user, userPwd);
var start = new Date();
var stmt = conn.createStatement();
var results = stmt.executeQuery(query);
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetTab = sheet.getSheetByName(tab);
var cell = sheetTab.getRange(startCell);
var numCols = results.getMetaData().getColumnCount();
var numRows = sheetTab.getLastRow();
var headers ;
var row =0;
clearRange(tab,startCell,numRows, numCols);
for(var i = 1; i <= numCols; i++){
headers = results.getMetaData().getColumnName(i);
cell.offset(row, i-1).setValue(headers);
}
while (results.next()) {
var rowString = '';
for (var col = 0; col < numCols; col++) {
rowString += results.getString(col + 1) + '\t';
cell.offset(row +1, col).setValue(results.getString(col +1 ));
}
row++
Logger.log(rowString)
}
results.close();
stmt.close();
var end = new Date();
Logger.log('Time elapsed: %sms', end - start);
}
If you don't want to create your own solution, check out SeekWell. It allows you to connect to databases and write SQL queries directly in Sheets from a sidebar add-on. You can also schedule queries to automatically run daily, hourly or every five minutes.
Disclaimer: I made this.
Ok, I finally managed to make it work.
Some few tips: Script is executed at Google's server, so connection must be done over inetrnet, i.e. connect string should be something like "jdbc:sqlserver://172.217.29.206:7000;databaseName=XXXX" and make sure that ip/port mentioned at connect string, can reach you database from outside world. Open port at firewall, make IP forwarding at router and use dyndns or similar services if you do not have a valid domain etc. Sheet ID is the large id string that appeals at your google document's url.

How to write a script that does "Save for web" for mutiple resolutions in Adobe Illustrator?

It's tedious to have to click to "Save for web" and change the resolution each time I want to create the image as a different resolution. Is there a way to write a script to automatically achieve this, for multiple resolutions as one?
For that i myself use this function
function saveDocumentAsPng(d, width, height) {
var fileName = d.fullName.toString();
if(fileName.lastIndexOf(".") >= 0) { fileName = fileName.substr(0, fileName.lastIndexOf("."));}
fileName += "_wxh.png".replace("w", width).replace("h", height);
var exportOptions = new ExportOptionsPNG24();
exportOptions.horizontalScale = exportOptions.verticalScale = 100 * Math.max(width/d.width, height/d.height);
var file = new File(fileName);
app.activeDocument = d;
d.exportFile(file, ExportType.PNG24, exportOptions);
}
Note that it names a resulting png's with “_[width]x[height]” suffix.
I wrote my function based on a sample from adobe's javascript reference http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/illustrator/scripting/illustrator_scripting_reference_javascript_cs5.pdf (page 59).
This is an old post, but it inspired me to create a different version for my Android project that I'd like to share.
Just create a 144x144 pixels document and run this:
var doc = app.activeDocument;
// This is the scale factor that you can see in "Percent" textbox of
// the "Save for Web..." dialog box while changing the size of the image
var scale = [100, 66.67, 50, 33.33]
// This is the image size for the PNGs files names
var size = [144, 96, 72, 48]
for(var i = 0; i<4; i++)
{
var fileName = doc.fullName.toString();
if (fileName.lastIndexOf(".") >= 0) {
// Get the file name without the extension
fileName = fileName.substr(0, fileName.lastIndexOf("."));
}
// Name each file with yours size to avoid overwrite
fileName += "_wxh.png".replace("w", size[i]).replace("h", size[i]);
var exportOptions = new ExportOptionsPNG24();
exportOptions.horizontalScale = exportOptions.verticalScale = scale[i];
exportOptions.artBoardClipping = true;
var file = new File(fileName);
doc.exportFile(file, ExportType.PNG24, exportOptions);
}
Window.alert ("Successfully exported!", "Success");
Thank you!
Here is the script that will export all files of the selected folder into PNG. You can specify resolution in this code and image quality will be good. In this code by default resolution is 600
var folder = Folder.selectDialog();
if (folder) {
var files = folder.getFiles("*.ai");
for (var i = 0; i < files.length; i++) {
var currentFile = files[i];
app.open(currentFile);
var activeDocument = app.activeDocument;
var pngFolder = Folder(currentFile.path + "/PNG");
if (!pngFolder.exists)
pngFolder.create();
var fileName = activeDocument.name.split('.')[0] + ".png";
var destinationFile = File(pngFolder + "/" + fileName);
// Export Artboard where you can set resolution for an image. Set to 600 by default in code.
var opts = new ImageCaptureOptions();
opts.resolution = 600;
opts.antiAliasing = true;
opts.transparency = true;
try {
activeDocument.imageCapture(new File(destinationFile), activeDocument.geometricBounds, opts);
} catch (e) {
}
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
currentFile = null;
}
}
If you want to export in jpg format, just change extension of the file in the code in the following line
var fileName = activeDocument.name.split('.')[0] + ".png";
change to
var fileName = activeDocument.name.split('.')[0] + ".jpg"; // For jpg
Also, you can change the name of the file and where the exported file will be stored according to your requirement.
Hope my answer will help you.

How do I programmatically capture and replicate Ai path shape?

I'm using ExtendScript for scripting Adobe Illustrator. I was wondering if there was a sneaky way or a script available to programmatically capture and then replicate a path shape, sort of JavaScript's .toSource() equivalent.
Thanks
Try this:
main();
function main(){
var doc = app.activeDocument; // get the active doc
var coords = new Array(); // make a new array for the coords of the path
var directions = new Array();
var sel = doc.selection[0];// get first object in selection
if(sel == null) {
// check if something is slected
alert ("You need to sevlect a path");
return;
}
var points = sel.pathPoints;// isolate pathpoints
// loop points
for (var i = 0; i < points.length; i++) {
// this could be done in one lines
// just to see whats going on line like
//~ coords.push(new Array(points[i].anchor[0],points[i].anchor[1]));
var p = points[i]; // the point
var a = p.anchor; // his anchor
var px = a[0];// x
var py = a[1]; // y
var ldir = p.leftDirection;
var rdir = p.rightDirection;
directions.push(new Array(ldir,rdir));
coords.push(new Array(px,py));// push into new array of array
}
var new_path = doc.pathItems.add(); // add a new pathitem
new_path.setEntirePath(coords);// now build the path
// check if path was closed
if(sel.closed){
new_path.closed = true;
}
// set the left and right directions
for(var j = 0; j < new_path.pathPoints.length;j++){
new_path.pathPoints[j].leftDirection = directions[j][0];
new_path.pathPoints[j].rightDirection = directions[j][1];
}
}