/appengine/conversion/conversion.go

https://code.google.com/p/appengine-go/ · Go · 118 lines · 88 code · 12 blank · 18 comment · 21 complexity · ccabcbfa2670ac93bc592b8be046291c MD5 · raw file

  1. // Copyright 2011 Google Inc. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. /*
  5. Package conversion implements an interface to the document conversion service.
  6. Example:
  7. TODO
  8. */
  9. package conversion
  10. import (
  11. "errors"
  12. "fmt"
  13. "strconv"
  14. "appengine"
  15. "appengine_internal"
  16. "code.google.com/p/goprotobuf/proto"
  17. conversion_proto "appengine_internal/conversion"
  18. )
  19. // Asset is a single document asset.
  20. type Asset struct {
  21. Name string // optional
  22. Data []byte
  23. Type string // MIME type (optional)
  24. }
  25. // Document represents a collection of assets.
  26. type Document struct {
  27. Assets []Asset // must have at least one element
  28. }
  29. // Options represents document conversion options.
  30. // Each field is optional.
  31. type Options struct {
  32. ImageWidth int
  33. // TODO: FirstPage, LastPage, InputLanguage
  34. }
  35. func (o *Options) toFlags() (map[string]string, error) {
  36. // TODO: Sanity check values.
  37. m := make(map[string]string)
  38. if o.ImageWidth != 0 {
  39. m["imageWidth"] = strconv.Itoa(o.ImageWidth)
  40. }
  41. return m, nil
  42. }
  43. // Convert converts the document to the given MIME type.
  44. // opts may be nil.
  45. func (d *Document) Convert(c appengine.Context, mimeType string, opts *Options) (*Document, error) {
  46. req := &conversion_proto.ConversionRequest{
  47. Conversion: []*conversion_proto.ConversionInput{
  48. &conversion_proto.ConversionInput{
  49. Input: &conversion_proto.DocumentInfo{},
  50. OutputMimeType: &mimeType,
  51. },
  52. },
  53. }
  54. for _, asset := range d.Assets {
  55. a := &conversion_proto.AssetInfo{
  56. Data: asset.Data,
  57. }
  58. if asset.Name != "" {
  59. a.Name = &asset.Name
  60. }
  61. if asset.Type != "" {
  62. a.MimeType = &asset.Type
  63. }
  64. req.Conversion[0].Input.Asset = append(req.Conversion[0].Input.Asset, a)
  65. }
  66. if opts != nil {
  67. f, err := opts.toFlags()
  68. if err != nil {
  69. return nil, err
  70. }
  71. for k, v := range f {
  72. req.Conversion[0].Flag = append(req.Conversion[0].Flag, &conversion_proto.ConversionInput_AuxData{
  73. Key: proto.String(k),
  74. Value: proto.String(v),
  75. })
  76. }
  77. }
  78. res := &conversion_proto.ConversionResponse{}
  79. if err := c.Call("conversion", "Convert", req, res, nil); err != nil {
  80. return nil, err
  81. }
  82. // We only support one conversion at a time, so the following code assumes that.
  83. if len(res.Result) != 1 {
  84. return nil, fmt.Errorf("conversion: requested conversion of one doc, but got %d back", len(res.Result))
  85. }
  86. if ec := *res.Result[0].ErrorCode; ec != conversion_proto.ConversionServiceError_OK {
  87. return nil, fmt.Errorf("conversion: operation failed: %v", ec)
  88. }
  89. output := res.Result[0].Output
  90. if output == nil {
  91. return nil, errors.New("conversion: output is nil")
  92. }
  93. doc := &Document{}
  94. for _, asset := range output.Asset {
  95. doc.Assets = append(doc.Assets, Asset{
  96. Name: proto.GetString(asset.Name),
  97. Data: asset.Data,
  98. Type: proto.GetString(asset.MimeType),
  99. })
  100. }
  101. return doc, nil
  102. }
  103. func init() {
  104. appengine_internal.RegisterErrorCodeMap("conversion", conversion_proto.ConversionServiceError_ErrorCode_name)
  105. }