7

C# を使用して Google クラウド プリントを使用しようとしています。インターネットには、Josh Goebel を書いた1 つの例しかありません。完全な例は公開しません。印刷するファイルを送信する唯一の方法は次のとおりです。


public CloudPrintJob PrintDocument(string printerId, string title, byte[] document)
    {
        try
        {
            string authCode;
            if (!Authorize(out authCode))
                return new CloudPrintJob() { success = false };

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com/cloudprint/submit?output=json");
            request.Method = "POST";

            string queryString =
                "printerid=" + HttpUtility.UrlEncode(printerId) +
                "&capabilities=" + HttpUtility.UrlEncode("") +
                "&contentType=" + HttpUtility.UrlEncode("application/pdf") +
                "&title=" + HttpUtility.UrlEncode(title) +
                "&content=" + HttpUtility.UrlEncode(Convert.ToBase64String(document));

            byte[] data = new ASCIIEncoding().GetBytes(queryString);

            request.Headers.Add("X-CloudPrint-Proxy", Source);
            request.Headers.Add("Authorization", "GoogleLogin auth=" + authCode);

            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            Stream stream = request.GetRequestStream();
            stream.Write(data, 0, data.Length);
            stream.Close();

            // Get response
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd();

            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(CloudPrintJob));
            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(responseContent));
            CloudPrintJob printJob = serializer.ReadObject(ms) as CloudPrintJob;

            return printJob;
        }
        catch (Exception ex)
        {
            return new CloudPrintJob() { success = false, message = ex.Message };
        }
    }

このコードを実行すると、プリンターのインターフェイスが表示されますが、印刷は行われません。プリンターのインターフェイスでは、印刷するページ数が 0 であり、ファイル サイズがプリンターに送信したサイズと一致しません。

Google クラウド プリントでは、タスク (ジョブ) が正常に追加されたと表示されますが、Google クラウド プリントのインターフェイスでは、ドキュメントの名前の横に「エラー」と表示されます。

HttpUtility.UrlEncodeまたはConvert.ToBase64Stringに問題があるのではないかと思いましたが、逆変換を試みました - すべてが機能します。

誰にもアイデアはありますか?

4

4 に答える 4

7

この質問が少し古いことを理解していますが、最近、私が仕事で行っていることについてこれを見なければなりませんでした.投稿されたサンプルコードは正しい方向に私を始めましたが、それにはかなりの時間がかかりました完全に機能するようにします。

「プリンターのリスト」機能は説明どおりに正常に機能しましたが、送信を適切に機能させることができませんでした。OP で説明されているように、エラーが発生しました。

Fiddler を使用して Chrome で実際の送信要求をプロファイリングし、Google の Web サイトで PHP サンプル コードを調べたところ、送信がマルチパート MIME メッセージである必要があるか、正しく機能しないことがわかりました。

これは、最終的に送信操作が機能するようになった HTTP POST メッセージの例です。要求 URL で gcp プリンター ID を渡す必要があり、データ (PDF、JPG、または PNG) を Base64 でエンコードし、正しい MIME タイプを設定する必要があることに注意してください (application/pdf、image/jpeg .. .) 「コンテンツ」ブロックの場合 (以下のリストの最後のブロック):

POST http://www.google.com/cloudprint/submit?printerid=<printerid>&output=json HTTP/1.1
Host: www.google.com
Content-Length: 44544
X-CloudPrint-Proxy: Google-JS
Content-Type: multipart/form-data; boundary=----CloudPrintFormBoundaryqeq6g6ncj5v7

------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="capabilities"

{"capabilities":[{}]}
------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="contentType"

dataUrl
------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="title"

zodiac-pig-pic.jpg
------CloudPrintFormBoundaryqeq6g6ncj5v7
Content-Disposition: form-data; name="content"

data:image/jpeg;base64,JVBERi0xLjQKJeHp69MKMiAwIG...2NgolJUVPRg==
------CloudPrintFormBoundaryqeq6g6ncj5v7--

私をつまずかせたのは、ヘッダーで指定された Boundary 値に実際の使用量よりも 2 つ少ないハイフン (--) があることでした (なぜ機能しないのか不思議に思っているものを見つめているときは明らかではありません!)、最後の境界インスタンスの末尾に 2 つの追加のハイフンがあり、(request.ServicePoint.Expect100Continue = false を使用して) C# の Expect100Continue ヘッダーを削除する必要がありました。

更新:誰かを助ける場合に備えて、私が当時書いた完全なコードを次に示します。

using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using GoogleCloudPrintServices.DTO;

namespace GoogleCloudPrintServices.Support
{
    public class GoogleCloudPrint
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Source { get; set; }

        private const int ServiceTimeout = 10000;

        public GoogleCloudPrint (String source)
        {
            Source = source;
        }

        public CloudPrintJob PrintDocument (string printerId, string title, byte[] document, String mimeType)
        {
            try
            {
                string authCode;
                if (!Authorize (out authCode))
                    return new CloudPrintJob { success = false };

                var b64 = Convert.ToBase64String (document);

                var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/submit?output=json&printerid=" + printerId);
                request.Method = "POST";

                // Setup the web request
                SetupWebRequest (request);

                // Add the headers
                request.Headers.Add ("X-CloudPrint-Proxy", Source);
                request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);

                var p = new PostData ();

                p.Params.Add (new PostDataParam { Name = "printerid", Value = printerId, Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "capabilities", Value = "{\"capabilities\":[{}]}", Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "contentType", Value = "dataUrl", Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "title", Value = title, Type = PostDataParamType.Field });

                p.Params.Add (new PostDataParam
                {
                    Name = "content",
                    Type = PostDataParamType.Field,
                    Value = "data:" + mimeType + ";base64," + b64
                });

                var postData = p.GetPostData ();
                Trace.WriteLine (postData);

                byte[] data = Encoding.UTF8.GetBytes (postData);

                request.ContentType = "multipart/form-data; boundary=" + p.Boundary;

                Stream stream = request.GetRequestStream ();
                stream.Write (data, 0, data.Length);
                stream.Close ();

                // Get response
                var response = (HttpWebResponse)request.GetResponse ();
                var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();

                var serializer = new DataContractJsonSerializer (typeof (CloudPrintJob));
                var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
                var printJob = serializer.ReadObject (ms) as CloudPrintJob;

                return printJob;
            }
            catch (Exception ex)
            {
                return new CloudPrintJob { success = false, message = ex.Message };
            }
        }

        public CloudPrinters Printers
        {
            get
            {
                var printers = new CloudPrinters ();

                string authCode;
                if (!Authorize (out authCode))
                    return new CloudPrinters { success = false };

                try
                {
                    var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/search?output=json");
                    request.Method = "POST";

                    // Setup the web request
                    SetupWebRequest (request);

                    // Add the headers
                    request.Headers.Add ("X-CloudPrint-Proxy", Source);
                    request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);

                    request.ContentType = "application/x-www-form-urlencoded";
                    request.ContentLength = 0;

                    var response = (HttpWebResponse)request.GetResponse ();
                    var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();

                    var serializer = new DataContractJsonSerializer (typeof (CloudPrinters));
                    var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
                    printers = serializer.ReadObject (ms) as CloudPrinters;

                    return printers;
                }
                catch (Exception)
                {
                    return printers;
                }
            }
        }

        private bool Authorize (out string authCode)
        {
            var result = false;
            authCode = "";

            var queryString = String.Format ("https://www.google.com/accounts/ClientLogin?accountType=HOSTED_OR_GOOGLE&Email={0}&Passwd={1}&service=cloudprint&source={2}",
                UserName, Password, Source);
            var request = (HttpWebRequest)WebRequest.Create (queryString);

            // Setup the web request
            SetupWebRequest (request);

            var response = (HttpWebResponse)request.GetResponse ();
            var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();

            var split = responseContent.Split ('\n');
            foreach (var s in split)
            {
                var nvsplit = s.Split ('=');
                if (nvsplit.Length == 2)
                {
                    if (nvsplit[0] == "Auth")
                    {
                        authCode = nvsplit[1];
                        result = true;
                    }
                }
            }

            return result;
        }

        private static void SetupWebRequest (HttpWebRequest webRequest)
        {
            // Get the details
            var appSettings = ConfigurationManager.AppSettings;

            // Create some credentials
            if (!String.IsNullOrWhiteSpace (appSettings["ProxyUsername"]))
            {
                var cred = new NetworkCredential (appSettings["ProxyUsername"], appSettings["ProxyPassword"],
                                                 appSettings["ProxyDomain"]);

                // Set the credentials
                webRequest.Credentials = cred;
                webRequest.Proxy = WebRequest.DefaultWebProxy;
                webRequest.Proxy.Credentials = cred;
            }

            // Set the timeout
            webRequest.Timeout = ServiceTimeout;
            webRequest.ServicePoint.ConnectionLeaseTimeout = ServiceTimeout;
            webRequest.ServicePoint.MaxIdleTime = ServiceTimeout;

            // Turn off the 100's
            webRequest.ServicePoint.Expect100Continue = false;
        }
    }
}



using System.Runtime.Serialization;

namespace GoogleCloudPrintServices.DTO
{
    [DataContract]
    public class CloudPrinter
    {
        [DataMember (Order = 0)]
        public string id { get; set; }

        [DataMember (Order = 1)]
        public string name { get; set; }

        [DataMember (Order = 2)]
        public string description { get; set; }

        [DataMember (Order = 3)]
        public string proxy { get; set; }

        [DataMember (Order = 4)]
        public string status { get; set; }

        [DataMember (Order = 5)]
        public string capsHash { get; set; }

        [DataMember (Order = 6)]
        public string createTime { get; set; }

        [DataMember (Order = 7)]
        public string updateTime { get; set; }

        [DataMember (Order = 8)]
        public string accessTime { get; set; }

        [DataMember (Order = 9)]
        public bool confirmed { get; set; }

        [DataMember (Order = 10)]
        public int numberOfDocuments { get; set; }

        [DataMember (Order = 11)]
        public int numberOfPages { get; set; }
    }
}



using System.Collections.Generic;
using System.Runtime.Serialization;

namespace GoogleCloudPrintServices.DTO
{
    [DataContract]
    public class CloudPrinters
    {
        [DataMember (Order = 0)]
        public bool success { get; set; }

        [DataMember (Order = 1)]
        public List<CloudPrinter> printers { get; set; }
    }
}



using System.Runtime.Serialization;

namespace GoogleCloudPrintServices.DTO
{
    [DataContract]
    public class CloudPrintJob
    {
        [DataMember (Order = 0)]
        public bool success { get; set; }

        [DataMember (Order = 1)]
        public string message { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Text;

namespace GoogleCloudPrintServices.Support
{
    internal class PostData
    {
        private const String CRLF = "\r\n";

        public string Boundary { get; set; }
        private List<PostDataParam> _mParams;

        public List<PostDataParam> Params
        {
            get { return _mParams; }
            set { _mParams = value; }
        }

        public PostData ()
        {
            // Get boundary, default is --AaB03x
            Boundary = "----CloudPrintFormBoundary" + DateTime.UtcNow;

            // The set of parameters
            _mParams = new List<PostDataParam> ();
        }

        public string GetPostData ()
        {
            var sb = new StringBuilder ();
            foreach (var p in _mParams)
            {
                sb.Append ("--" + Boundary).Append (CRLF);

                if (p.Type == PostDataParamType.File)
                {
                    sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", p.Name, p.FileName)).Append (CRLF);
                    sb.Append ("Content-Type: ").Append (p.FileMimeType).Append (CRLF);
                    sb.Append ("Content-Transfer-Encoding: base64").Append (CRLF);
                    sb.Append ("").Append (CRLF);
                    sb.Append (p.Value).Append (CRLF);
                }
                else
                {
                    sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"", p.Name)).Append (CRLF);
                    sb.Append ("").Append (CRLF);
                    sb.Append (p.Value).Append (CRLF);
                }
            }

            sb.Append ("--" + Boundary + "--").Append (CRLF);

            return sb.ToString ();
        }
    }

    public enum PostDataParamType
    {
        Field,
        File
    }

    public class PostDataParam
    {
        public string Name { get; set; }
        public string FileName { get; set; }
        public string FileMimeType { get; set; }
        public string Value { get; set; }
        public PostDataParamType Type { get; set; }

        public PostDataParam ()
        {
            FileMimeType = "text/plain";
        }
    }
}
于 2012-04-17T08:16:03.670 に答える
7

これに苦労している人のために、サービス アカウントで Google クラウド プリントを使用する方法に関するコードと手順を含む github リポジトリを作成し、新しい OAuth2 認証方法用に更新しました。

https://github.com/io7/GoogleCloudPrint

于 2015-08-19T07:49:14.040 に答える
3

問題の原因は、サーバーに送信したデータのエンコードにあるようです。この場合の最も信頼できる解決策は、ドキュメントを送信するときにデータ URI スキームを使用することです。これを行うには、contentType を "dataUrl" に設定し、データを次の形式で渡す必要があります: "data:application/pdf;base64," + Convert.ToBase64String(document)

于 2011-10-27T05:18:47.367 に答える