• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

InDesign Folder to JPG Folder Exporter - the Script ignores JPEG Prefrences!

Enthusiast ,
Apr 26, 2021 Apr 26, 2021

Copy link to clipboard

Copied

Hi Experts,

I'm trying to build script that convert whole InDesign Folder Contains (*.indd) Files to Folder (*.jpg) Files, the Problem here that i cannot understand that it ignores JPEG Prefrences!, no Error , the files always Exported as RGB -300 ppi only and ignoring user entry of JPEG Prefrences, i tried hard to figure the problem but maybe i miss something, please help.

 

//InDesign Folder to JPG Folder Exporter

if(app.documents.length > 0){
    // DIALOG -- UI
    // ======
    var dialog = new Window("dialog"); 
        dialog.text = "Indesign Folder to JPG folder Exporter"; 
        dialog.preferredSize.width = 300; 
        dialog.preferredSize.height = 300; 
        dialog.orientation = "column"; 
        dialog.alignChildren = ["center","top"]; 
        dialog.spacing = 10; 
        dialog.margins = 16; 

    // GROUP1
    // ======
    var group1 = dialog.add("group", undefined, {name: "group1"}); 
        group1.orientation = "row"; 
        group1.alignChildren = ["left","center"]; 
        group1.spacing = 10; 
        group1.margins = 0; 

    // PANEL1 - Export Settings
    // ======
    var panel1 = group1.add("panel", undefined, undefined, {name: "panel1"}); 
        panel1.text = "Export Settings"; 
        panel1.preferredSize.width = 300; 
        panel1.orientation = "column"; 
        panel1.alignChildren = ["left","top"]; 
        panel1.spacing = 10; 
        panel1.margins = 10; 

    // GROUP2 - Color Mode
    // ======
    var group2 = panel1.add("group", undefined, {name: "group2"}); 
        group2.orientation = "row"; 
        group2.alignChildren = ["left","center"]; 
        group2.spacing = 10; 
        group2.margins = 0;
        
    //Color Mode
   //===========
    var statictext1 = group2.add("statictext", undefined, undefined, {name: "statictext1"}); 
        statictext1.text = "Color Mode : "; 
        statictext1.preferredSize.width = 100; 

    var dropdown1_array = ["RGB","CMYK","Gray"]; 
    var dropdown1 = group2.add("dropdownlist", undefined, undefined, {name: "dropdown1", items: dropdown1_array}); 
        dropdown1.selection = 0; 
        dropdown1.preferredSize.width = 150; 
    
    // GROUP3
    // ======
    var group3 = panel1.add("group", undefined, {name: "group3"}); 
    
   //Export Quality
   //===========
    var statictext2 = group3.add("statictext", undefined, undefined, {name: "statictext2"}); 
        statictext2.text = "Export Quality : "; 
        statictext2.preferredSize.width = 100; 

    var dropdown2_array = ["Low","Medium","High","Maximum"]; 
    var dropdown2 = group3.add("dropdownlist", undefined, undefined, {name: "dropdown2", items: dropdown2_array}); 
        dropdown2.selection = 3; 
        dropdown2.preferredSize.width = 150; 

    // GROUP4 - JPEG Encoding
    // ======
    var group4 = panel1.add("group", undefined, {name: "group4"}); 
        group4.orientation = "row"; 
        group4.alignChildren = ["left","center"]; 
        group4.spacing = 10; 
        group4.margins = 0; 
    
    // JPEG Encoding
    //=============
    var statictext3 = group4.add("statictext", undefined, undefined, {name: "statictext3"}); 
        statictext3.text = "JPEG Format : "; 
        statictext3.preferredSize.width = 100; 

    var dropdown3_array = ["Baseline Encoding","Progressive"]; 
    var dropdown3 = group4.add("dropdownlist", undefined, undefined, {name: "dropdown3", items: dropdown3_array}); 
        dropdown3.selection = 0; 
        dropdown3.preferredSize.width = 150; 

    // GROUP5 - Resolution
    // ======
    var group5 = panel1.add("group", undefined, {name: "group5"}); 
        group5.orientation = "row"; 
        group5.alignChildren = ["left","center"]; 
        group5.spacing = 10; 
        group5.margins = 0; 

    var statictext4 = group5.add("statictext", undefined, undefined, {name: "statictext4"}); 
        statictext4.text = "Resolution : "; 
        statictext4.preferredSize.width = 100; 

    var dropdown4_array = ["72","150","300","600"]; 
    //var dropdown4_array = ["72","96","150","300","600","1200","2400"];
    var dropdown4 = group5.add("dropdownlist", undefined, undefined, {name: "dropdown4", items: dropdown4_array}); 
        dropdown4.selection = 3; 

    // GROUP6
    // ======
    var group6 = panel1.add("group", undefined, {name: "group6"}); 
        group6.orientation = "row"; 
        group6.alignChildren = ["left","center"]; 
        group6.spacing = 10; 
        group6.margins = 0; 

    var divider2 = panel1.add("panel", undefined, undefined, {name: "divider2"}); 
        divider2.alignment = "fill"; 

    // GROUP7
    // ======
    var group7 = panel1.add("group", undefined, {name: "group7"}); 
        group7.orientation = "column"; 
        group7.alignChildren = ["left","top"]; 
        group7.spacing = 10; 
        group7.margins = 0; 

    // ButtonsGroup
    // ======
    var myButtonGroup = dialog.add("group", undefined, {name: "group8"}); 
        myButtonGroup.preferredSize.width = 300; 
        myButtonGroup.orientation = "row"; 
        myButtonGroup.alignChildren = ["center","center"]; 
        myButtonGroup.spacing = 10; 
        myButtonGroup.margins = 0; 
        //OK and Cancel
       //Adding OK Button
       var Button1 = myButtonGroup.add ("button", undefined, "OK");
       var Button2 = myButtonGroup.add ("button", undefined, "Cancel");
       var Button3 = myButtonGroup.add ("button", undefined, "About");

//What Happened if User Hit About Button - All the OnClick Callers Must Came Before Showing Dialogs
Button3.onClick = function() {alertAbout();};
function alertAbout() {
alert("InDesign Folder to JPG Folder Export Indd's folder to JPG's folder" , "About");
}

//After Drawing Interface
//Showing the Dialog - We Will Show as Varaible So We Can Correctly Use Cancel Button (w.Show() are One time in Code)
var a = dialog.show()

//What Happened if User Hit Cancel
if(a == 2){   
  alert("Canceled by User!");
  exit(0);
}

    //Drop Down Conditions
    //JPEG Color Space
      if(dropdown1.selection == "RGB"){
            app.jpegExportPreferences.jpegColorSpace = JpegColorSpaceEnum.RGB;
            }
        else if(dropdown1.selection == "CMYK"){
            app.jpegExportPreferences.jpegColorSpace = JpegColorSpaceEnum.CMYK;
            }
        else if(dropdown1.selection == "GRAY"){
            app.jpegExportPreferences.jpegColorSpace = JpegColorSpaceEnum.GRAY;
            }
    //JPEG Quality
        if(dropdown2.selection == "Low"){
            app.jpegExportPreferences.jpegQuality =JPEGOptionsQuality.LOW;
            }
        else if(dropdown2.selection == "Medium"){
            app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.MEDIUM;
            }
        else if(dropdown2.selection == "High"){
            app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.HIGH;
            }
        else if(dropdown2.selection == "Maximum"){
            app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.MAXIMUM;
            }
        //JPEG Encoding
        if(dropdown3.selection == "Baseline Encoding"){
            app.jpegExportPreferences.jpegRenderingStyle = JPEGOptionsFormat.BASELINE_ENCODING;
            }
        else if(dropdown3.selection == "Progressive"){
            app.jpegExportPreferences.jpegRenderingStyle = JPEGOptionsFormat.PROGRESSIVE_ENCODING;
            }
         //JPEG Resolution
        if(dropdown4.selection == "72"){
            app.jpegExportPreferences.exportResolution = 72;
            }
        else if(dropdown4.selection == "150"){
            app.jpegExportPreferences.exportResolution = 150;
            }
        else if(dropdown4.selection == "300"){
            app.jpegExportPreferences.exportResolution = 300;
            }
        else if(dropdown4.selection == "600"){
            app.jpegExportPreferences.exportResolution = 600;
            }
        
        // Start the Program
        var outputToJPG = function (doc, folder) {
         //Apply JPEG Export
        var exportFile = new File(folder.fsName + "/" + doc.name.slice(0, doc.name.lastIndexOf(".")) + ".jpg");
    try {
    doc.exportFile(ExportFormat.JPG, exportFile);    
    } catch (e) {
        alert("Couldn't export " + exportFile.name + " for this reason: " + e);
    }
};

//Select Indd Docs
        var myFolder = Folder.selectDialog("Select a folder with INDD files to export");
        if (myFolder == null) exit();
        var myFilelist = [];
        var myAllFilesList = myFolder.getFiles();

        for (var f = 0; f < myAllFilesList.length; f++) {
            var myFile = myAllFilesList[f];
            if (myFile instanceof File && myFile.name.match(/\.indd$/i)) {
            myFilelist.push(myFile);
}
}

if (myFilelist.length == 0) {
    alert("No files to open.", "Export to JPG");
    exit();
}
}
   
//User Selected JPG Export Folder
var folder = Folder.selectDialog("Please select a folder to save Exported JPG's to");
var currInteractPrefs = app.scriptPreferences.userInteractionLevel;
app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
var docs = app.open(myFilelist, false);

for (var i = 0; i < docs.length; i++) {
    for(var p = 0; p < app.documents[0].pages.length; p++) {  
         app.jpegExportPreferences.pageString = app.documents[0].pages[p].name;
         outputToJPG(docs[i], folder);
}
}
app.scriptPreferences.userInteractionLevel = currInteractPrefs;
    

 

So Please help to fix the problem

Thanks in Advance

Best

M.Hasanain

Best
Mohammad Hasanin
TOPICS
Scripting

Views

296

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 2 Correct answers

Community Expert , Apr 26, 2021 Apr 26, 2021

I think it is because you are not capturing the dialog results as variables, and you are not destroying the dialog window.

 

Not sure if this helps, but InDesign has a built in dialog API, which I think is easier to use. So here I’m setting up 4 empty variables at the top to hold the dialog results, constructing the dialog,  capturing the results in the global variables, before calling the main script and destroying the dialog:

 

 


//dialog result variables
var colorMode, cList, imageQuality, q
...

Votes

Translate

Translate
Community Expert , Apr 26, 2021 Apr 26, 2021

I checked your script and apart from other things that I didn't understand why you wrote it the way it is. I see that the problem is with checking the value of the dropdown. You are using it like

if(dropdown4.selection== "72")

However, if you use it as follows it starts working

if(dropdown4.selection.text == "72")

The type of dropdown selection is ListItem, so I used the property that specifically is a string value. Make this change in all the if-else clauses and it will work

-Manan

Votes

Translate

Translate
Community Expert ,
Apr 26, 2021 Apr 26, 2021

Copy link to clipboard

Copied

I think it is because you are not capturing the dialog results as variables, and you are not destroying the dialog window.

 

Not sure if this helps, but InDesign has a built in dialog API, which I think is easier to use. So here I’m setting up 4 empty variables at the top to hold the dialog results, constructing the dialog,  capturing the results in the global variables, before calling the main script and destroying the dialog:

 

 


//dialog result variables
var colorMode, cList, imageQuality, qList, formatMethod, formList, imageRes; 

//check for a doc
if (app.documents.length > 0) {
    var doc = app.activeDocument;
    makeDialog();
} else {alert("Please open a document and try again.")}

/**
* Make the  dialog 
*/

function makeDialog(){
    //the dialog name
    var theDialog = app.dialogs.add({name:"JPEG Export", canCancel:true});
    with(theDialog){
        with(dialogColumns.add()){
            //The panel name
            with(dialogRows.add()){
                    staticTexts.add({staticLabel:"Export Settings", staticAlignment:StaticAlignmentOptions.LEFT_ALIGN, minWidth: 150});
            }
            with(borderPanels.add()){
                //add labels
                with(dialogColumns.add()){
                    staticTexts.add({staticLabel:"Color Mode:"});
                    staticTexts.add({staticLabel:"Export Quality:"});
                    staticTexts.add({staticLabel:"JPEG Format:"});
                    staticTexts.add({staticLabel:"Resolution:"});
                }
                //dropdowns and combos
                with(dialogColumns.add()){
                    cList = ["RGB", "CMYK", "Gray"]
                    colorMode = dropdowns.add({stringList:cList, selectedIndex:0});
                    
                    qList = ["Maximum", "High", "Medium", "Low"]
                    imageQuality = dropdowns.add({stringList:qList, selectedIndex:0});
                    
                    formList = ["Baseline Standard", "Baseline Optimized", "Progressive"]
                    formatMethod = dropdowns.add({stringList:formList, selectedIndex:0});
                    
                    imageRes = integerComboboxes.add({stringList:["72", "96", "150", "300", "600", "1200", "2400"], editValue:72, maximumValue:2400, minimumValue:1, smallNudge:1, largeNudge:10});
                }
            }
        }
    }
	
    //the results
    var res = theDialog.show();
    if(res == true){
        
        imageQuality = qList[imageQuality.selectedIndex]
        formatMethod = formList[formatMethod.selectedIndex]
        imageRes = imageRes.editValue
        colorMode = cList[colorMode.selectedIndex]
        
        exportScript();
        
        theDialog.destroy();
	}else{
        theDialog.destroy();
    }
}



/**
* Export Script.
*/

function exportScript(){
    alert("Dialog Results:\r" + imageQuality + "\r" + formatMethod + "\r" + imageRes + "\r" + colorMode)
    
    //set JPEG Prefs
    if (colorMode == "RGB") {
        app.jpegExportPreferences.jpegColorSpace = JpegColorSpaceEnum.RGB;
    } else if (colorMode == "CMYK"){
        app.jpegExportPreferences.jpegColorSpace = JpegColorSpaceEnum.CMYK;
    } else {
        app.jpegExportPreferences.jpegColorSpace = JpegColorSpaceEnum.GRAY;
    }
    
    if (imageQuality == "Maximum") {
        app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.MAXIMUM;
    } else if (imageQuality == "High"){
        app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.HIGH;
    } else if (imageQuality == "Medium"){
        app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.MEDIUM;
    } else {
        app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.LOW;
    }

    app.jpegExportPreferences.exportResolution = imageRes;
    
    //export script...
}






 

 

https://www.indesignjs.de/extendscriptAPI/indesign-latest/#Dialog.html#d1e588933

https://www.indesignjs.de/extendscriptAPI/indesign-latest/#DialogColumn.html#d1e593097

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 26, 2021 Apr 26, 2021

Copy link to clipboard

Copied

Thank you very much mr.rob day , that's cool and i can rebuilt my scripts ui in this way, thanks a lot

Best 

M.Hasanain

Best
Mohammad Hasanin

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 26, 2021 Apr 26, 2021

Copy link to clipboard

Copied

LATEST

I use this as a dialog template: It covers most of the column properties—dropdowns, checkbox, radio buttons, etc.

 

//result variables
var pdfDropdown, colorDropdown, foodDropdown, foodList, angleCombo, integerCombo, realCombo, percentCombo, measureCombo,
enablePanel, ckBox, colRadio, pageRadio, spreadRadio,
realEdit, intEdit, percentEdit, measureEdit, angleEdit, textEditField;
var pageWidth;

//check for a doc
if (app.documents.length > 0) {
var doc = app.activeDocument;
pageWidth = doc.documentPreferences.pageWidth
makeDialog();
} else {alert("Please open a document and try again.")}

/**
* Make the dialog
* @Return void
*/

function makeDialog(){
//the dialog name
var theDialog = app.dialogs.add({name:"Dialog Components", canCancel:true});
with(theDialog){
with(dialogColumns.add()){
//Panel Dropdowns and Combos
with(dialogRows.add()){
staticTexts.add({staticLabel:"Panel 1 Dropdowns", staticAlignment:StaticAlignmentOptions.LEFT_ALIGN, minWidth: 150});
}
with(borderPanels.add()){
with(dialogColumns.add()){
staticTexts.add({staticLabel:"PDF Drop Down:"});
staticTexts.add({staticLabel:"Swatches Drop Down:"});
staticTexts.add({staticLabel:"String Drop Down:"});
staticTexts.add({staticLabel:"Angle Combo:"});
staticTexts.add({staticLabel:"Integer Combo:"});
staticTexts.add({staticLabel:"Real Combo:"});
staticTexts.add({staticLabel:"Percent Combo:"});
staticTexts.add({staticLabel:"Measurement Combo:"});
}
with(dialogColumns.add()){
pdfDropdown = dropdowns.add({stringList:getPresets(app.pdfExportPresets), selectedIndex:3, minWidth:80});
colorDropdown = dropdowns.add({stringList:getPresets(app.swatches), selectedIndex:2, minWidth:80});
foodList = ["Mustard", "Relish", "Ketchup"];
foodDropdown = dropdowns.add({stringList:foodList, selectedIndex:0, minWidth:80});
angleCombo = angleComboboxes.add({stringList:["0", "90", "180"], editValue:0, maximumValue:360, minimumValue:0, smallNudge:1, largeNudge:10, minWidth:50});
integerCombo = integerComboboxes.add({stringList:["1", "2", "3"], editValue:0, maximumValue:100, minimumValue:0, smallNudge:1, largeNudge:10, minWidth:50});
realCombo = realComboboxes.add({stringList:[".1", ".2", ".3"], editValue:0, maximumValue:1, minimumValue:0, smallNudge:.01, largeNudge:.1, minWidth:50});
percentCombo = percentComboboxes.add({stringList:["10", "15", "20"], editValue:10, maximumValue:100, minimumValue:0, smallNudge:1, largeNudge:10, minWidth:50});
measureCombo = measurementComboboxes.add({stringList:[pageWidth.toString(), "600", "800", "1200", "1800"], editUnits:MeasurementUnits.PIXELS, editValue:pageWidth});
}
}
//Panel 2 Enabling
with(dialogRows.add()){
staticTexts.add({staticLabel:"Panel 2 Enabling", staticAlignment:StaticAlignmentOptions.LEFT_ALIGN, minWidth: 150});
}
enablePanel = enablingGroups.add({checkedState:false, minWidth:150})
with(enablePanel){
with(dialogColumns.add()){
staticTexts.add({staticLabel:"Check Box"});
staticTexts.add({staticLabel:"Columns"});
staticTexts.add({staticLabel:"Pages"});
staticTexts.add({staticLabel:"Spreads"});
}
with(dialogColumns.add()){
ckBox = checkboxControls.add({checkedState:false, minWidth:150});
with(radiobuttonGroups.add()){
colRadio = radiobuttonControls.add({checkedState:true});
pageRadio = radiobuttonControls.add({checkedState:true});
spreadRadio = radiobuttonControls.add({checkedState:true});
}
}
}
//Panel 3 Editable
with(dialogRows.add()){
staticTexts.add({staticLabel:"Panel 3 Edit Boxes", staticAlignment:StaticAlignmentOptions.LEFT_ALIGN, minWidth: 150});
}
with(borderPanels.add()){
with(dialogColumns.add()){
staticTexts.add({staticLabel:"Real Edit:"});
staticTexts.add({staticLabel:"Integer Edit:"});
staticTexts.add({staticLabel:"Percent Edit:"});
staticTexts.add({staticLabel:"Measurement Edit:"});
staticTexts.add({staticLabel:"Angle Edit:"});
staticTexts.add({staticLabel:"Text Edit:"});
}
with(dialogColumns.add()){
realEdit = realEditboxes.add({editValue:0, maximumValue:10, minimumValue:0, smallNudge:.01, largeNudge:.1, minWidth:50});
intEdit = integerEditboxes.add({editValue:1, maximumValue:100, minimumValue:0, smallNudge:1, largeNudge:10, minWidth:50});
percentEdit = percentEditboxes.add({editValue:15, maximumValue:100, minimumValue:0, smallNudge:1, largeNudge:10, minWidth:50});
measureEdit = measurementEditboxes.add({editUnits:MeasurementUnits.MILLIMETERS, editValue:0, maximumValue:1000, minimumValue:0, smallNudge:1, largeNudge:10, minWidth:90});
angleEdit = angleEditboxes.add({editValue:0, maximumValue:360, minimumValue:0, smallNudge:1, largeNudge:10, minWidth:50});
textEditField = textEditboxes.add({editContents:"Hello World!", minWidth:150});
}
}
}
}

//the dialog results
var res = theDialog.show();
if(res == true){
pdfDropdown = app.pdfExportPresets.item(pdfDropdown.selectedIndex);
colorDropdown = app.swatches.item(colorDropdown.selectedIndex);
foodDropdown = foodList[foodDropdown.selectedIndex];
angleCombo = angleCombo.editValue;
integerCombo = integerCombo.editValue;
realCombo = realCombo.editValue;
percentCombo = percentCombo.editValue;
measureCombo = measureCombo.editValue;//returns points

enablePanel = enablePanel.checkedState
ckBox = ckBox.checkedState;
colRadio = colRadio.checkedState
pageRadio = pageRadio.checkedState
spreadRadio = spreadRadio.checkedState

realEdit = realEdit.editValue;
intEdit = intEdit.editValue;
percentEdit = percentEdit.editValue;
measureEdit = measureEdit.editValue;//returns points
angleEdit = angleEdit.editValue;
textEditField = textEditField.editContents

main()
}else{
theDialog.destroy();
}
}



/**
* Script.
* @Return void
*/

function main(){

$.writeln("\nPDF Preset = " + pdfDropdown.name +"\nColor = " + colorDropdown.name +"\nFood = " + foodDropdown +
"\ncombo angle= " + angleCombo + "\ncombo integer= " + integerCombo +"\ncombo real= " + realCombo +
"\ncombo percent= " + percentCombo + "\ncombo measurement= "+ measureCombo +
"\nenable panel= "+ enablePanel + "\ncheck box= "+ ckBox +"\ncolumn radio= "+ colRadio + "\npage radio= "+ pageRadio + "\nspread radio= "+ spreadRadio +
"\nreal edit = " + realEdit + "\ninteger edit = " + intEdit + "\npercent edit = " + percentEdit +"\nmeasure edit= "+ measureEdit +
"\nangle edit= "+ angleEdit +"\ntext edit= "+ textEditField)
}



/**
* Returns a list of item names from the provided collection
* @Param the collection
* @Return array of names
*
*/
function getPresets(p){
var a = new Array;
for(var i = 0; i < p.length; i++){
a.push(p.item(i).name);
}
return a
}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 26, 2021 Apr 26, 2021

Copy link to clipboard

Copied

I checked your script and apart from other things that I didn't understand why you wrote it the way it is. I see that the problem is with checking the value of the dropdown. You are using it like

if(dropdown4.selection== "72")

However, if you use it as follows it starts working

if(dropdown4.selection.text == "72")

The type of dropdown selection is ListItem, so I used the property that specifically is a string value. Make this change in all the if-else clauses and it will work

-Manan

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 26, 2021 Apr 26, 2021

Copy link to clipboard

Copied

Thank you very much Mr. Manan, i Wrote it this way because i still learning scripting so i need to put everything as blocks! so it will be easy for me to understand, thanks a lot, it works!.

Best

M.Hasanain

Best
Mohammad Hasanin

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines