1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file.
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/utility/cloud_print/pwg_encoder.h"
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <algorithm>
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/logging.h"
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/utility/cloud_print/bitmap_image.h"
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "net/base/big_endian.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace cloud_print {
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kBitsPerColor = 8;
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kColorSpace = 19;  // sRGB.
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kColorOrder = 0;  // chunky.
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kNumColors = 3;
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kBitsPerPixel = kNumColors * kBitsPerColor;
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const char kPwgKeyword[] = "RaS2";
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderSize = 1796;
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderHwResolutionHorizontal = 276;
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderHwResolutionVertical = 280;
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsWidth = 372;
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsHeight = 376;
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsBitsPerColor = 384;
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsBitsPerPixel = 388;
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsBytesPerLine = 392;
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsColorOrder = 396;
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsColorSpace = 400;
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsNumColors = 420;
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderPwgTotalPageCount = 452;
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kPwgMaxPackedRows = 256;
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kPwgMaxPackedPixels = 128;
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)PwgEncoder::PwgEncoder() {}
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)inline void encodePixelFromRGBA(const uint8* pixel, std::string* output) {
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->push_back(static_cast<char>(pixel[0]));
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->push_back(static_cast<char>(pixel[1]));
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->push_back(static_cast<char>(pixel[2]));
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)inline void encodePixelFromBGRA(const uint8* pixel, std::string* output) {
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->push_back(static_cast<char>(pixel[2]));
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->push_back(static_cast<char>(pixel[1]));
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->push_back(static_cast<char>(pixel[0]));
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void PwgEncoder::EncodeDocumentHeader(std::string* output) const {
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->clear();
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->append(kPwgKeyword, 4);
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void PwgEncoder::EncodePageHeader(const BitmapImage& image, const uint32 dpi,
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  const uint32 total_pages,
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  std::string* output) const {
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  char header[kHeaderSize];
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memset(header, 0, kHeaderSize);
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderHwResolutionHorizontal, dpi);
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderHwResolutionVertical, dpi);
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsWidth, image.size().width());
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsHeight,
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              image.size().height());
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsBitsPerColor, kBitsPerColor);
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsBitsPerPixel, kBitsPerPixel);
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsBytesPerLine,
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                              (kBitsPerPixel * image.size().width() + 7) / 8);
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsColorOrder, kColorOrder);
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsColorSpace, kColorSpace);
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderCupsNumColors, kNumColors);
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  net::WriteBigEndian<uint32>(header + kHeaderPwgTotalPageCount, total_pages);
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->append(header, kHeaderSize);
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool PwgEncoder::EncodeRowFrom32Bit(const uint8* row, const int width,
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                    const int color_space,
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                    std::string* output) const {
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void (*pixel_encoder)(const uint8*, std::string*);
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  switch (color_space) {
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case BitmapImage::RGBA:
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pixel_encoder = &encodePixelFromRGBA;
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case BitmapImage::BGRA:
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pixel_encoder = &encodePixelFromBGRA;
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      break;
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    default:
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      LOG(ERROR) << "Unsupported colorspace.";
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return false;
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Converts the list of uint8 to uint32 as every pixels contains 4 bytes
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // of information and comparison of elements is easier. The actual management
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // of the bytes of the pixel is done by template function P on the original
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // array to avoid endian problems.
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const uint32* pos = reinterpret_cast<const uint32*>(row);
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const uint32* row_end = pos + width;
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // According to PWG-raster, a sequence of N identical pixels (up to 128)
108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // can be encoded by a byte N-1, followed by the information on
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // that pixel. Any generic sequence of N pixels (up to 128) can be encoded
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // with (signed) byte 1-N, followed by the information on the N pixels.
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Notice that for sequences of 1 pixel there is no difference between
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // the two encodings.
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // It is usually better to encode every largest sequence of > 2 identical
115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // pixels together because it saves the most space. Every other pixel should
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // be encoded in the smallest number of generic sequences.
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  while (pos != row_end) {
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const uint32* it = pos + 1;
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const uint32* end = std::min(pos + kPwgMaxPackedPixels, row_end);
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Counts how many identical pixels (up to 128).
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    while (it != end && *pos == *it) {
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      it++;
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (it != pos + 1) {  // More than one pixel
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      output->push_back(static_cast<char>((it - pos) - 1));
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pixel_encoder(reinterpret_cast<const uint8*>(pos), output);
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pos = it;
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else {
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Finds how many pixels each different from the previous one (up to 128).
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      while (it != end && *it != *(it - 1)) {
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        it++;
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Optimization: ignores the last pixel of the sequence if it is followed
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // by an identical pixel, as it is more convenient for it to be the start
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // of a new sequence of identical pixels. Notice that we don't compare
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // to end, but row_end.
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (it != row_end && *it == *(it - 1)) {
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        it--;
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      output->push_back(static_cast<char>(1 - (it - pos)));
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      while (pos != it) {
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        pixel_encoder(reinterpret_cast<const uint8*>(pos++), output);
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)inline const uint8* PwgEncoder::GetRow(const BitmapImage& image,
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                       int row) const {
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return image.pixel_data() + row * image.size().width() * image.channels();
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Given a pointer to a struct Image, create a PWG of the image and
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// put the compressed image data in the std::string.  Returns true on success.
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// The content of the std::string is undefined on failure.
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool PwgEncoder::EncodePage(const BitmapImage& image,
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            const uint32 dpi,
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            const uint32 total_pages,
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            std::string* output) const {
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // For now only some 4-channel colorspaces are supported.
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (image.channels() != 4) {
164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LOG(ERROR) << "Unsupported colorspace.";
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EncodePageHeader(image, dpi, total_pages, output);
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int row_size = image.size().width() * image.channels();
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int row_number = 0;
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  while (row_number < image.size().height()) {
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const uint8* current_row = GetRow(image, row_number++);
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int num_identical_rows = 1;
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // We count how many times the current row is repeated.
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    while (num_identical_rows < kPwgMaxPackedRows
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           && row_number < image.size().height()
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           && !memcmp(current_row, GetRow(image, row_number), row_size)) {
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      num_identical_rows++;
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      row_number++;
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    output->push_back(static_cast<char>(num_identical_rows - 1));
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Both supported colorspaces have a 32-bit pixels information.
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!EncodeRowFrom32Bit(
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            current_row, image.size().width(), image.colorspace(), output)) {
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return false;
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace cloud_print
195