Document ExportImage command creates image file with different extensions - revit-api

There is a strange behavior when I try create an image from view in Revit via API. For some reason the target file sometimes is "png", sometimes "jpg" (for different View3D). As a workaround I check file existence and replace the extension, but I think it's not a good solution. The idea was taken from
https://thebuildingcoder.typepad.com/blog/2013/08/setting-a-default-3d-view-orientation.html
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
var tempFileName = Path.ChangeExtension(Path.GetRandomFileName(), "png");
string tempImageFile;
try
{
tempImageFile = Path.Combine(Path.GetTempPath(), tempFileName);
}
catch (IOException)
{
return Result.Failed;
}
var opt = new ImageExportOptions
{
ZoomType = ZoomFitType.Zoom,
FilePath = tempImageFile,
FitDirection = FitDirectionType.Horizontal,
HLRandWFViewsFileType = ImageFileType.PNG,
ImageResolution = ImageResolution.DPI_300,
};
doc.ExportImage(opt);
Debug.WriteLine(File.Exists(tempImageFile) ? "File exists." : "File does not exist.");
return Result.Succeeded;
}
}
Steps to reproduce:
Create external command (implement IExternalCommand interface)
Use provided above implementation of Execute method
Open Revit 2020 sample model (rac_basic_sample_project.rvt)
Select 3D Views->Selection Perspective (or Kitchen)
Execute external command
Check the result of doc.ExportImage(opt) command
AR: Result file has "jpg" extension instead of "png"
ER: File should be "png".
PS. If you select 3D Views->{3D} file has extension "png"
Look at screens

Related

Uploading PDF file to Google Drive folder and overwriting existing file

I am developing an app that uploads PDF files to a specific Google Drive folder. The file name includes the current date. The following code is for my DriveServiceHelper.class that is used to create a folder in Google Drive and then upload the PDF files into that folder using its folderID:
public class DriveServiceHelper {
Calendar c = Calendar.getInstance();
Date d = c.getTime();
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy");
String currentDate = df.format(d);
String ps_FolderKey;
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private Drive mDriveService;
public DriveServiceHelper(Drive mDriveService) {
this.mDriveService = mDriveService;
}
public Task<String> createFolder() {
return Tasks.call(mExecutor, () -> {
File folderMetadata = new File();
folderMetadata.setName("Covid Assessment Sheets");
folderMetadata.setMimeType("application/vnd.google-apps.folder");
File myFolder = null;
try {
myFolder = mDriveService.files().create(folderMetadata)
.setFields("id")
.execute();
System.out.println("Folder ID: " + myFolder.getId());
} catch (Exception e) {
e.printStackTrace();
}
if (myFolder == null) {
throw new IOException("Null result when requesting file creation");
}
ps_FolderKey = myFolder.getId();
return ps_FolderKey;
});
}
public Task<String> createFilePDF(String filePath, String folderId) {
return Tasks.call(mExecutor, () -> {
File fileMetaData = new File();
fileMetaData.setName("Covid Assessment # " + currentDate);
fileMetaData.setParents(Collections.singletonList(folderId));
java.io.File file = new java.io.File(filePath);
FileContent mediaContent = new FileContent("application/pdf", file);
File myFile = null;
try {
myFile = mDriveService.files().create(fileMetaData, mediaContent).execute();
} catch (Exception e) {
e.printStackTrace();
}
if (myFile == null) {
throw new IOException("Null result when requesting file creation");
}
return myFile.getId();
});
}
}
When uploading the same PDF to a Google Drive folder, I want to overwrite files with the same name, but instead duplicate files are created in the folder as the fileID assigned is different even if file name is the same.
Please help me understand how I should go about this, to automatically overwrite/replace files that already exist with the same name (each file is differentiated by date), and a new PDF file is created if the PDF file does not exist in the folder.
I understand that I might be using the deprecated Drive API, but I was unable to find other solutions online to help me implement what I need. I also came across solutions that include queries to search for existing Google Drive files, but I am not sure I understand how to use it to make it work for me.
Thank you
Google Drive supports multiple files with the same name
Thus, by creating a file with an already existing name, you will not automatically overwrite the old file.
Instead you should do the following:
Use the method Files:list with the query name = 'Covid Assessment Sheets' to find the already existing file(s) with the same name
If desired, you can narrow down the results by also specifying the mimeType and the parent folder (parents)
Retrieve the id of the list result(s)
Use the method Files:delete to delete the existing file
Proceed to create a new file as you are already doing
In Java this would look as following:
FileList result = DriveService.files().list()
.setQ("name = 'Covid Assessment Sheets'");
.setFields("files(id)")
.execute();
List<File> files = result.getFiles();
for (File file : files) {
DriveService.files().delete(file.getId()).execute();
}
An alternative approach would be to update the contents of the already existing file instead of creating a new one.

C# SharePoint CSOM change file properties after upload

I have searched and found several examples of how to do this, but I can't make them work - well part of it doesn't work.
I can perform the file upload, but the following attempt to change properties fail.
I'm attempting to upload a file from a base64 payload - this part works - but when I afterwards attempt to edit the properties (custom column) associated with the file, the code fails.
Here is the code (simplified for readability):
(note that props is a collection of custom objects (FileProperty) with a name and a value attribute).
using (ClientContext context = new ClientContext("<sharepoint_server_url>"))
{
context.Credentials = new SharePointOnlineCredentials(<usr>,<secure_pwd>);
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(Convert.FromBase64String(<base64_content>)))
{
File.SaveBinaryDirect(context, <relative_path>, ms, true);
}
// file is uploaded - so far so good!
// attempt to edit properties of the file.
if (props != null)
{
if (props.Count > 0)
{
File newFile = context.Web.GetFileByServerRelativeUrl(<relative_path>);
context.Load(newFile);
context.ExecuteQuery();
newFile.CheckOut();
ListItem item = newFile.ListItemAllFields;
foreach (FileProperty fp in props)
{
item[fp.name] = fp.value;
}
item.Update();
newFile.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
}
}
}
This code throws an exception in the part where I try to update the properties.
Message: The file was not found.
Can anyone tell me what is wrong with this example or provide another example on how to do this?
Also, a question - is there a way to address a file by a unique ID which is the same regardless of where in the SharePoint server the file is located or moved to?
I hope someone can help me out - thanks :)
Ok, I found a solution to my problem. I don't know why this works better, it just does.
For all I know, I'm doing the exact same thing, just in another way - maybe someone else who knows more about SharePoint than me (which isn't much) can explain why this works while the first example I posted doesn't.
Previous to the code shown, I ensure that <site_url> doesn't end with "/" and that <library_name> doesn't start or end with "/" and that <file_name> doesn't start or end with "/".
With the code below I can uplaod a file and update properties, in my case i changed "Title" and a custom column "CustCulomnA" and it workes.
using (ClientContext context = new ClientContext(<site_url>))
{
context.Credentials = new SharePointOnlineCredentials(<usr>, <secure_pwd>);
FileCreationInformation fci = new FileCreationInformation()
{
Url = <file_name>,
Content = Convert.FromBase64String(<base64_content>),
Overwrite = true
};
Web web = context.Web;
List lib = web.Lists.GetByTitle(<library_name>);
lib.RootFolder.Files.Add(fci);
context.ExecuteQuery();
response.message = "uploaded";
if (props != null)
{
if (props.Count > 0)
{
File newFile = context.Web.GetFileByUrl(<site_url> +"/"+ <library_name> + "/" + <file_name>);
context.Load(newFile);
context.ExecuteQuery();
newFile.CheckOut();
ListItem item = newFile.ListItemAllFields;
foreach (FileProperty fp in props)
{
item[fp.name] = fp.value;
}
item.Update();
newFile.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
context.ExecuteQuery();
Make sure the file server relative url is valid in this case.
For example if the complete url is:
https://zheguo.sharepoint.com/sites/test/Shared%20Documents/test.jpg
Then relative url should be
/sites/test/Shared%20Documents/test.jpg
And you can also use GetFileByUrl method, passing the complete file url like this:
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Web web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();
File file = web.GetFileByUrl("https://zheguo.sharepoint.com/sites/test/Shared%20Documents/test.jpg");
clientContext.Load(file);
clientContext.ExecuteQuery();
file.CheckOut();
ListItem item = file.ListItemAllFields;
item["Title"] = "Test";
item.Update();
file.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
clientContext.ExecuteQuery();
}

GENERATE MULTIPLE TEXT FILES IN ACUMATICA LOCALLY

How can I generate several text files at the same time locally?
I am using the method:
throw new PXRedirectToFileException (file, true);
![enter image description here][1]
However, this method only generates 1 text file. I need more than 1 text file to be generated at a time.
List<object> data1099Misc = new List<object> { };
ARInvoice ari = Base.Document.Current;
foreach (xvrFSCab diot in PXSelect<xvrFSCab,
Where<xvrFSCab.invoiceNbr,
In<Required<xvrFSCab.invoiceNbr>>>>.Select(Base, ari.InvoiceNbr))
{
data1099Misc.Add(CreatePayerARecord(diot));
}
FixedLengthFile flatFile = new FixedLengthFile();
flatFile.WriteToFile(data1099Misc, sw);
sw.Flush();
sw.FlushAsync();
int cont = 0;
while ( cont<3)
{
cont = cont + 1;
string path = "DIOTJOSE" + ".txt";
PX.SM.FileInfo file = new PX.SM.FileInfo(path, null, stream.ToArray());
throw new PXRedirectToFileException(file, true);
}
Acumatica had the same issue when they had to open multiple reports at one click (with RedirectException).
For this reason Acumatica supports multiple RequiredException only for Reports.
They have a method called "CombineReport" that works with multiple PXReportRequiredException (PXReportsRedirectList)
Sad part is that they did not make something for other RequiredException or RedirectException
I tried to make my own "Combine" method but I was not able to create it just because the RedirectHelper.TryRedirect method use hardcoded types of the RedirectException inside body instead to use an generic or base object :(

Can I delete a file in Acumatica via the API?

I'm creating a file in Acumatica by calling an action from the API, so that I can retrieve the file in my application.
Is it possible to delete the file via API after I'm done with it? I'd rather not have it cluttering up my Acumatica database.
Failing this, is there a recommended cleanup approach for these files?
Found examples of how to delete a file from within Acumatica, as well as how to save a new version of an existing file! The below implementation saves a new version but has the deletion method commented out. Because I built this into my report generation process, I'm not later deleting the report via API, but it would be easy to translate a deletion into an action callable by the API.
private IEnumerable ExportReport(PXAdapter adapter, string reportID, Dictionary<String, String> parameters)
{
//Press save if the SO is not completed
if (Base.Document.Current.Completed == false)
{
Base.Save.Press();
}
PX.SM.FileInfo file = null;
using (Report report = PXReportTools.LoadReport(reportID, null))
{
if (report == null)
{
throw new Exception("Unable to access Acumatica report writer for specified report : " + reportID);
}
PXReportTools.InitReportParameters(report, parameters, PXSettingProvider.Instance.Default);
ReportNode reportNode = ReportProcessor.ProcessReport(report);
IRenderFilter renderFilter = ReportProcessor.GetRenderer(ReportProcessor.FilterPdf);
//Generate the PDF
byte[] data = PX.Reports.Mail.Message.GenerateReport(reportNode, ReportProcessor.FilterPdf).First();
file = new PX.SM.FileInfo(reportNode.ExportFileName + ".pdf", null, data);
//Save the PDF to the SO
UploadFileMaintenance graph = new UploadFileMaintenance();
//Check to see if a file with this name already exists
Guid[] files = PXNoteAttribute.GetFileNotes(Base.Document.Cache, Base.Document.Current);
foreach (Guid fileID in files)
{
FileInfo existingFile = graph.GetFileWithNoData(fileID);
if (existingFile.Name == reportNode.ExportFileName + ".pdf")
{
//If we later decide we want to delete previous versions instead of saving them, this can be changed to
//UploadFileMaintenance.DeleteFile(existingFile.UID);
//But in the meantime, for history purposes, set the UID of the new file to that of the existing file so we can save it as a new version.
file.UID = existingFile.UID;
}
}
//Save the file with the setting to create a new version if one already exists based on the UID
graph.SaveFile(file, FileExistsAction.CreateVersion);
//Save the note attribute so we can find it again.
PXNoteAttribute.AttachFile(Base.Document.Cache, Base.Document.Current, file);
}
//Return the info on the file
return adapter.Get();
}
The response from Acumatica:
S-b (Screen-base) API allows clean way of downloading report generated as file. C-b (Contract-base) simply does not have this feature added. I suggest you provided feedback here: feedback.acumatica.com (EDIT: Done! https://feedback.acumatica.com/ideas/ACU-I-1852)
I think couple of workaround are:
1) use s-b using login from c-b to generate report and get as file (see example below), or
2) create another method to delete the file once required report file is downloaded. For that, you will need to pass back FileID or something to identify for deletion.
example of #1
using (DefaultSoapClient sc = new DefaultSoapClient("DefaultSoap1"))
{
string sharedCookie;
using (new OperationContextScope(sc.InnerChannel))
{
sc.Login("admin", "123", "Company", null, null);
var responseMessageProperty = (HttpResponseMessageProperty)
OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
sharedCookie = responseMessageProperty.Headers.Get("Set-Cookie");
}
try
{
Screen scr = new Screen(); // add reference to report e.g. http://localhost/Demo2018R2/Soap/SO641010.asmx
scr.CookieContainer = new System.Net.CookieContainer();
scr.CookieContainer.SetCookies(new Uri(scr.Url), sharedCookie);
var schema = scr.GetSchema();
var commands = new Command[]
{
new Value { LinkedCommand = schema.Parameters.OrderType, Value = "SO" },
new Value { LinkedCommand = schema.Parameters.OrderNumber, Value = "SO004425" },
schema.ReportResults.PdfContent
};
var data = scr.Submit(commands);
if(data != null && data.Length > 0)
{
System.IO.File.WriteAllBytes(#"c:\Temp\SalesOrder.pdf",
Convert.FromBase64String(data[0].ReportResults.PdfContent.Value));
}
}
finally
{
sc.Logout();
}
}
Hope this helps. Also, it would be great if you update the stackover post based on these suggestions.
Thanks
Nayan Mansinha
Lead - Developer Support | Acumatica

Error Running jsx file from Indesign to export each text frame as a .txt file

Last year my colleague helped to build a script for Indesign.
Subsequently, after a system update we no longer have the script as Indesign CS6 was reinstalled, all we have is a version as below.
Using this code in Adobe Indesign to export each text frame that begins with a particular Paragraph stylesheet "PRODUCT HEADING" however I get an error message when I run the script...
Script is based on the ExportAllStories.jsx bundled with InDesign, plus a few mods found online.
//ExportAllStories.jsx
//An InDesign CS6 JavaScript
/*
###BUILDINFO### "ExportAllStories.jsx" 3.0.0 15 December 2009
*/
//Exports all stories in an InDesign document in a specified text format.
//
//For more on InDesign scripting, go to http://www.adobe.com/products/indesign/scripting/index.html
//or visit the InDesign Scripting User to User forum at http://www.adobeforums.com
//
main();
function main(){
//Make certain that user interaction (display of dialogs, etc.) is turned on.
app.scriptPreferences.userInteractionLevel = UserInteractionLevels.interactWithAll;
if(app.documents.length != 0){
if (app.activeDocument.stories.length != 0){
myDisplayDialog();
}
else{
alert("The document does not contain any text. Please open a document containing text and try again.");
}
}
else{
alert("No documents are open. Please open a document and try again.");
}
}
function myDisplayDialog(){
with(myDialog = app.dialogs.add({name:"ExportAllStories"})){
//Add a dialog column.
myDialogColumn = dialogColumns.add()
with(myDialogColumn){
with(borderPanels.add()){
staticTexts.add({staticLabel:"Export as:"});
with(myExportFormatButtons = radiobuttonGroups.add()){
radiobuttonControls.add({staticLabel:"Text Only", checkedState:true});
radiobuttonControls.add({staticLabel:"RTF"});
radiobuttonControls.add({staticLabel:"InDesign Tagged Text"});
}
}
}
myReturn = myDialog.show();
if (myReturn == true){
//Get the values from the dialog box.
myExportFormat = myExportFormatButtons.selectedButton;
myDialog.destroy;
myFolder= Folder.selectDialog ("Choose a Folder");
if((myFolder != null)&&(app.activeDocument.stories.length !=0)){
myExportAllStories(myExportFormat, myFolder);
}
}
else{
myDialog.destroy();
}
}
}
//myExportStories function takes care of exporting the stories.
//myExportFormat is a number from 0-2, where 0 = text only, 1 = rtf, and 3 = tagged text.
//myFolder is a reference to the folder in which you want to save your files.
function myExportAllStories(myExportFormat, myFolder){
for(myCounter = 0; myCounter < app.activeDocument.stories.length; myCounter++){
myStory = app.activeDocument.stories.item(myCounter);
myID = myStory.id;
switch(myExportFormat){
case 0:
myFormat = ExportFormat.textType;
myExtension = ".txt"
break;
case 1:
myFormat = ExportFormat.RTF;
myExtension = ".rtf"
break;
case 2:
myFormat = ExportFormat.taggedText;
myExtension = ".txt"
break;
}
if (myStory.paragraphs[0].appliedParagraphStyle.name == "PRODUCT HEADING"){
myFileName = myFileName.replace(/\s*$/,' ');
myFileName2 = myFileName.replace(/\//g, ' ');
myFilePath = myFolder + "/" + myFileName2;
myFile = new File(myFilePath);
myStory.exportFile(myFormat, myFile);
}
}
}
This results in an error on
if (myStory.paragraphs[0].appliedParagraphStyle.name == "PRODUCT HEADING"){
Any advice would be appreciated.
There is definitely a block of text with the style PRODUCT HEADING (all caps) in the Indesign File. We run Indesign CS6 as previous
thanks!
Your problem is most likely with this part: myStory.paragraphs[0]. If the story has no paragraphs this will give you an error.
You could add a condition before running this line, like this for example:
if(myStory.paragraphs.length){
if (myStory.paragraphs[0].appliedParagraphStyle.name == "PRODUCT HEADING"){
myFileName = myFileName.replace(/\s*$/,' ');
myFileName2 = myFileName.replace(/\//g, ' ');
myFilePath = myFolder + "/" + myFileName2;
myFile = new File(myFilePath);
myStory.exportFile(myFormat, myFile);
}
}

Resources