יום ראשון, 21 ביולי 2013

הפיכת מסמכי PDF לתמונה

פוסט זה נכתב לאחר שיטוט מסיבי באינטרנט למציאת פתרון, קודם אני אסביר את הבעיה:
ספריות רבות יוצרות מסמכי PDF, הבעייה שכדי שמסמך PDF יהיה תמונה הוא צריך להתרנדר כולו - וזה דבר שאין ספרייה שמטפלת בו. ספריות מפורסמות כמו iText או PDFsharp אינן יכולות לעשות זאת.
למרות ש PDFsharp מציעה את האפשרות הנחמדה לייצא מתוך הקובץ PDF תמונות.

ישנן ספריות חינמיות שטוענות שהן יכולות, אבל אני לא הצלחתי לעשות איתן כלום, כדו' 
 PDFClown, PdfRenderer. בנוסף התיעוד שלהם איננו מפותח מדי, וצריך לחפש פרוייקטים שמפורסמים באינטרנט כדי להבין כיצד לעבוד איתן.

ישנן ספריות שעולות מאות דולרים שמציעות פתרון, כמו soliddocuments
כמובן שלא בדקתי אותם.

וישנו פתרון נוסף, ברמת השרת. הספרייה GHOSTSCRIPT עושה זאת בצורה יפה.
נייבא לפרוייקט את הספרייה, מופיע בNuGet , ונעשה בקוד עצמו הפניה לספרייה עצמה gsdll32.dll
גם בספרייה זו ישנם מספר מוטציות של אותו קוד,שכולם מסמתמכות על אותו כותב.
הקוד שלי הצליח נמצא כאן או דוגמא נוספת כאן

 

יום שלישי, 9 ביולי 2013

קבלת קורדינאטות של מיקום בGoogle Map

לאחר שפתחנו חשבון מפתחים ב"גוגל מפתחים", ניכנס לAPI CONSOLE
נרשמנו, לאחר כמה זמן נקבל אישור ונקבל מספר מפתח, ובקטגוריהAPI ACCESS
נבחר את המחרוזת הארוכה שיש ב API key.
עכשיו ניתן להוסיף באתר שלנו תיבת חיפוש של מפות (במידה ונעבור את 25,000 חיפושים ביום או חצי מיליון בכלל, נצרך לשלם ולקבל חשבון עיסקי. די לצרה בשעתה...)
 
נוסיף את הסקריפט הזה באתר שלנו (החליפו את ה$$$$ ב api key)

 
<script src="https://maps.googleapis.com/maps/api/js?key=$$$$&sensor=false"></script>


וכל פעם תקבלו משתנה  google.maps שהוא מנהל את כל ההתנהלות שלכם מול הAPI של המפות.
(תוכלו לראות שנוספו לכם המון קבצי JS, הידד!)
נ.ב. אלו המשתנים והפונקציות שאנחנו מקבלים בעת קבלת האובייקט אצלנו 
google.maps

לצורך העניין בנינו תיבה שבה המחפש רושם את המקום שלו, ואנחנו רוצים להמיר אותה לקורדינטות - כדי שבפעם הבאה נוכל להציג למשתמש מפה, מבלי לחפש. ככה נוכל לחסוך את החיבור לגוגל והרבה תעבורת רשת. אם רוצים לקבל מפה קבועה.
 
var adress_map = $.trim($("#sMap").val());
var point = new Array("jb", "kb");

point = getCodeAddress(adress_map);
 
function getCodeAddress(address) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
  var point = new Array(results[0].geometry.location.jb, results[0].geometry.location.kb);
  return (point);
} else {
alert("אין אפשרות לקבל את הקודינאטות של המפה, תקלה: " + status)
}
});
}
 
 
 
 
 

 

 
 

יום ראשון, 30 ביוני 2013

גיבוי טבלאות וstored procedures בMSSQL

כמו כל דבר יש את שתי הדרכים, המגניבה שלא עוזרת, והמשעממת שעושה את העבודה.
אם אתם בעלי השרת: 
ניצור שני קבצים שהראשון מהווה פקודה בSQL, והשני יהיה פקודה שתריץ אותה מהמחשב האישי - ותעשה גיבוי בשרת עצמו.

נפתח את פנקס הרשימות ונכתב את הפקודה:
BACKUP DATABASE [שם מסד הנתונים] TO DISK = '\שם מסד הנתונים.bak' with init
 
 
נסגור את הקובץ ונשמור על שולחן העבודה, ונשמור זאת בסיומת SQL. ונקבל קובץ עם אייקון של SQL. לצורך העניין נקרא לו: backup.sql (כמה מפתיע...)
 
במידה ונריץ את הפקודה עצמה בSQL נקבל הודעה כזו:
 
Processed 472 pages for database 'שם מסד נתונים', file 'שם מסד נתונים_data' on file 1.
Processed 1 pages for database 'שם מסד נתונים', file 'שם מסד נתונים_log' on file 1.
BACKUP DATABASE successfully processed 473 pages in 0.061 seconds (60.578 MB/sec).

 
הקובץ גיבוי נשמר בשרת. עכשיו נושמים שנייה, ושוב נפתח את פנקס הכתובות ונכתוב קובץ נוסף, שיהווה את הפקודה שתריץ את הפקודה שכתבנו מקודם. נכתוב בקובץ עכשיו:
 
OSQL -U [שם משתמש] -P [סיסמא] -S [*המקום של השרת]  -i [מיקום הפקודה שמריצים**]
 
*80.80.800.180\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Backup\שם הטבלה
 
**C:\Users\sivan\Desktop\backup.sql
 
המיקום של הטבלה בשרת נכון על פי השרת שלי. איך גילתי?
אם ארצה לעשות את הפעולה גיבוי בשרת (שיכשל, כי אין לי הרשאות) קליק ימני על המסד נתונים ובחירת "משימות" (tasks) וגיבוי (back up) יראה לי היכן "אמור" הקובץ להישמר, וכך אני יודע היכן נמצא הטבלאות נתונים בשרת.
 
טוב, בכל אופן הקטע המגניב, נסגור את השורה ונשמור בקובץ בפרומט batch עם סיומת bat, בשם go.bat ונקבל אייקון של מערכת הפעלה. 
לחיצה על הקובץ ההפעלה תפעיל את הפקודה, ותבצע גיבוי של הנתונים שלי בשרת של החברה המארחת, שעוזר לי במקרה שהאתר קרס (ח"ו, טפו, טפו, טפו) לבקש מהם את הקובץ. כך בלחיצה אחת כל יום יש ראש שקט.
 
טוב, זה השיטה המגניבה, אבל לא ממש עוזרת אם אני רוצה אצלי את כל הנתונים.
לכן נבצע דרך הSQL שאילתה של גיבוי של הטבלאות יחד עם הנתונים שבתוכה, והכל יופיע בצורת פקודות הרצה.
 
איך?
שוב קליק ימני על מסד הנתונים, ובחירת "משימות", ובתוך משימות נבחר "יצירת סקריפים" ( Generate Scripts), נוכל לבחור מה לגבות:
טבלאות, סטור פרוסיג'יר, טבלאות משתמשים וכו'
 
במסך השני יש אפשרות לגבות הכל. אנו נבחר את האפשרות השנייה, לבחור בעצמנו מה לגבות ואז נבחר טבלאות (ישנה אפשרות לבחור רק חלק מהטבלאות).
 
ואז מגיע הקטע החשוב:
באופן דיפלוטיבי הSQL יוצר גיבוי של הסכמה של הנתונים, רק את הפקודות שיוצרות את הטבלאות, אבל אנחנו רוצים לגבות את הנתונים עצמם. בשביל כך נלחץ על כפתור Advanced (מתקדם), ותחת הקטגוריה   General באפשרות האחרונה Types of data to script נשנה ממצב של Sechema only למצב של Sechema and data.
 
מכאן NEXT יעשה את העבודה,  הוא ירוץ על כל הטבלאות ויהפוך אותן לפקודות של יצירת טבלה, ואת כל הנתונים הוא יכניס בצורה מסודרת בפקודת INSERT .
 
אם קרה משהו למסד נתונים (חס וחלילה, כנ"ל), פתיחת הקובץ טקסט הזה ולחיצת F5 יבנה לנו את הכל בחזרה.
 

יום חמישי, 27 ביוני 2013

הפנייה לדף אחר בJS ובJQ

נניח שאתם רוצים להפנות את הקליינט בסוף ריצה של פונקציה לאתר אחר, או אפילו בכניסה לאתר המשתמש יופנה לאתר אחר (למרות שזה פוגע בSEO), נשתמש באחת מהפקודות הבאות (הן מובאות לפי סדר העדיפות):

page = www.exp.co.il;

window.location.href = page;
window.location.replace(page);
location.assign(page);



או בJQ:

  $(location).attr('href', page);


יום שלישי, 12 במרץ 2013

המרת עברית לתווי ASCII ב#C

את הערכים המספריים של אותיות העבריות בטבלת ASCII תוכל למצוא כאן

הרעיון "המבצעי" היה להוסיף כגיבוי למחרוזת של עברית גם את תווי הASCII. הקוד קוצר מפרויקט שנועד לכתוב אותיות בעברית לתוך קובץ, אני קיצרתי את הפונקציה לקבלת מחרוזת והוצאת מחרוזת עם תווי הASCII:


public string convertStrToAscii(string strConvert)
    {
System.Collections.Generic.List<byte> encoded = new System.Collections.Generic.List<byte>();
        int value;
        foreach (char ch in strConvert)
        {
            value = Convert.ToInt32(ch);
            if (value >= 1488 && value <= 1488 + 27)
                value -= 1360;
            encoded.Add(Convert.ToByte(value));
        }

        string strEncoded = string.Join(",", encoded.ToArray());
        return (strEncoded + "_" + strConvert);
    }


יום ראשון, 10 במרץ 2013

mssql סינון השורות האחרונות כולל תנאי

יש לנו מערכת מאמרים, שנמצאת בטבלת article,  בהן העמודות:
- הת.ז. של המאמר (מספר) articleId 
- תמונת המאמר (מחרוזת) articlePic  
- תאריך הכנסת השורה (תאריך) articleDate 

ואנחנו רוצים להציג לקורא את חמשת המאמרים האחרונים, נשתמש בפקודת TOP, רק בכיוון ההפוך. פקודת TOP תיתן לנו את השורות הראשונות שהוזנו, ואנחנו צריכים את האחרונות.


SELECT TOP 5 * FROM dbo.article 
ORDER BY articleDate DESC

בשימוש בפקודה ORDER BY articleDate DESC אנחנו מסננים את חמשת התוצאות מהסוף. כמו מיון מת' עד א' [הפקודה ההפוכה היא ASC שמורה למיין מא' עד ת']

ישנה אפשרות אחרת, לבצע חיפוש מהי הכתבה האחרונה, ולבצע SELECT על כל הID של הכתבות מהמספר האחרון פחות חמש.
SELECT * FROM dbo.article 
WHERE articleId > 
(SELECT MAX(articleId) - 5 FROM dbo.article)

בבעיה שלנו נתבקשנו לעשות תנאי בתוך תנאי, למצוא את כל הכתבות שיש להם תמונה, ומתוכם למצוא את חמשת האחרונות.
כמובן שהחיפוש השני לא יעיל כאן, כי ייתכן שבכלל בכל הID ש"נתפס" בתוך השאילתא - לאף אחד אין בכלל תמונה. לכן חוזרים לשאילתא הראשונה ונשכלל אותה:
SELECT TOP 5 * FROM dbo.article 
WHERE articlePic  !=  ''
ORDER BY articleDate DESC
חשוב לשים לב שהתנאי הראשון הינו שעמודה picArticle  לא תהיה ריקה ולכן נשמש בהגדרת מחרוזת בMSSQL ע"י שני גרשיים (ולא מרכאות, כמו שאנחנו רגילים מJS או C#)

יום ראשון, 3 במרץ 2013

העלאת קבצים באופן אסכרוני בדף ASPX

בפוסט הקודם ניסינו לתת פתרון שלא עובד להעלאת קבצים בצורה שלא תעשה postback לדף. נכשלנו, והנה הפתרון הבא: 
שימוש בASPNET AJAX, דוגמא ליכולת של העלאת קבצים שכזו יש במדריך של הקובץ DLL הזה.

טוב, איך מתחילים?
ראשית, נוסיף את הקובץ לפרוייקט, מהאתר נוריד את הקובץ ZIP נחלץ את הקובץ AjaxControlToolkit.dll ונעשה לו הפנייה מהפרוייקט שלנו. לחצן ימני על הפרוויקט "הוסף הפנייה", ואז למטה נלחץ על browes ונוסיף את הקובץ.

שלב שני: הוספה לweb.config 


<system.web>
    <!--מונע מפוסטטבק לחזור לחלקו העליון של הדף במקרה של איפוס-->
    <pages maintainScrollPositionOnPostBack="true">
    <!--כדי שAJAXTOOLKIT יעבוד  -->
      <controls>
         <add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit" tagPrefix="ajaxToolkit"/>
      </controls>
</system.web>

שלב שלישי: הוספה לדף ASPX בראש העמוד
<%@ Register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="ajaxToolkit" %>


שלב רביעי: שים לב שהשם בכל הtagprefix זהה. אפשר לבחור שם אחר, ולשנות את "הקידומת" של האלמנטים בדף.
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <ajaxToolkit:AjaxFileUpload ID="AjaxFileUpload1" runat="server" OnUploadComplete="UploadComplete" />
       </ContentTemplate>
 </asp:UpdatePanel>

שלב חמישי, ואחרון: לתת לפקודה UploadComplete משמעות בדף CS:
  protected void UploadComplete(object sender, jaxControlToolkit.AjaxFileUploadEventArgs e)
    {
       
    }



מימוש של הקוד, נעזרתי בפרוייקט הזה, כדוגמא להעלאת תמונות. כדי שהתמונה גם תעלה וגם תופיע בדף נשתמש בכמה פקודות בJS.
נתחיל עם הפקד בASPX


<strong>העלאת תמונה</strong></label>
 
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <div style="direction: rtl;" class="textHide">
 
<ajaxToolkit:AsyncFileUpload ID="FileUploadImg" runat="server" Width="400px"
AllowedFileTypes="jpg,jpeg,gif,png,JPG,PNG,GIF,JPEG"
OnClientUploadError="uploadError"
OnClientUploadStarted="StartUpload"
OnClientUploadComplete="UploadComplete"
CompleteBackColor="Lime"
ErrorBackColor="Red"
ThrobberID="Throbber"
UploaderStyle="Modern"
OnUploadedComplete="FileUploadImg_UploadedComplete" />
 <asp:Label ID="Throbber" runat="server" Style="display: none">
<img src="../img/indicator.jpg" align="absmiddle" alt="loading" />
</asp:Label>
<asp:Label ID="lblStatus" runat="server" Style="font-family: Arial; font-size: small;" /><br />
           </div>
    </ContentTemplate>
</asp:UpdatePanel>
                <div id="Image1"></div>
נעבור למימוש בצד הקליינט של הפקודה, שעושה שלושה דברים:
א. שומרת את הקובץ בשרת.
ב. שולחת את התמונה לצד הקליינט.
ג. כותבת חיווי למשתמש על התמונה:
 

protected void FileUploadImg_UploadedComplete(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
    {
  //validate upload img typa && not null
     if ((FileUploadImg.PostedFile.ContentType.ToLower().StartsWith("image")) && (FileUploadImg.HasFile))
        {
   string filename = FileUploadImg.FileName;
 
    // string typeImg = FileUploadImg.ContentType;
    string directory = HttpRuntime.AppDomainAppPath + "img\\article\\";


// Create and save bitmap of the content of the fileUpload control in memory
      Bitmap originalBMP = new Bitmap(FileUploadImg.FileContent);
            originalBMP.Save(directory + filename);

             //send name file to clinet
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "newfile", "window.parent.$find('" + FileUploadImg.ClientID + "').newFileName='" + filename + "';", true);

            // Once finished with the bitmap objects, we deallocate them.
            originalBMP.Dispose();

            // Write a message to inform the user all is OK
string deImg = "שם הקובץחדש: " + filename;
            deImg += "גודלדל: " + FileUploadImg.PostedFile.ContentLength.ToString() + "KB";
            deImg += "סוגג: " + FileUploadImg.PostedFile.ContentType;
            imgLable.Text = deImg;

            // Display the image to the user
            Image1.Visible = true;
            Image1.ImageUrl = @"/img/article/tn_" + filename;

        }
 
 
        else { lblStatus.Text =
"אין קובץ להעלאה או הקובץ אינו תמונה תקנית";
 

}
 
    }uואי\ואי
 
 <div id="Image1"></d>
ואיך אפשר בלי JS שיטפל בתמונה הנשלחת בצד לקוח:
 
//valide img
function validateIMG() {
    var result = false;
    var IMGfile = document.getElementById("MainContent_FileUploadImg").value;
    if (IMGfile != "") {
        var accept = "png,gif,jpg,jpeg,bmp".split(',');
        var getExtention = IMGfile.split('.');
        var extention = getExtention[getExtention.length - 1].toLowerCase(); //if is GIF etc.
        for (i = 0; i < accept.length; i++) {
            if (accept[i] == extention) {
                result = true;
                break;
            }
        }
        if (!result) {
            alert("allowed file extention are png,gif,jpg,jpeg,bmp");
        }
    }
    else {
        alert("select image to Upload");
    }
    return result;
}
//js for fileupload
function StartUpload(sender, args) {
    document.getElementById('MainContent_lblStatus').innerText = 'טוען קובץועןקובץ';
}
function uploadError(sender, args) {
    document.getElementById('MainContent_lblStatus').innerText = args.get_fileName(),
        "<span style='color:red;'>" + args.get_errorMessage() + "</span>";
}
function UploadComplete(sender, args) {
    var filename = sender.newFileName; // args.get_fileName();
    var contentType = args.get_contentType();
    var text = "שםשם הקובץבץ: " + filename + "בגודלל: " + args.get_length() + " KB";
    if (contentType.length > 0) {
        text += "מסוגג: '" + contentType + "'.";
    }
    document.getElementById('MainContent_lblStatus').innerText = text;
    //save data for server
    document.getElementById("MainContent_nameNewPicArticle").value = filename.toString();
    //add pic to ui
    inserteImge(filename, "Image1")
}
function inserteImge(filename, ElementFatherName) {
    var newImg = document.createElement("img");
    newImg.src = "../img/article/" + filename;
    newImg.id = "picArticle";
    //add img
    var my_div = document.getElementById(ElementFatherName);
    my_div.appendChild(newImg);
}

נ.ב. הקוד מועתק מקוד מורכב יותר, אז אני מקווה שהכל נכון. והכנסתי את השלד של הקוד בצורה נכונה.