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)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/big_endian.h"
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/logging.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/utility/cloud_print/bitmap_image.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 kColorOrder = 0;  // chunky.
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Coefficients used to convert from RGB to monochrome.
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kRedCoefficient = 2125;
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kGreenCoefficient = 7154;
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const uint32 kBlueCoefficient = 721;
250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kColorCoefficientDenominator = 10000;
260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char* kPwgKeyword = "RaS2";
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderSize = 1796;
300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kHeaderCupsDuplex = 272;
310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kHeaderCupsHwResolutionHorizontal = 276;
320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kHeaderCupsHwResolutionVertical = 280;
330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kHeaderCupsTumble = 368;
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsWidth = 372;
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsHeight = 376;
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsBitsPerColor = 384;
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsBitsPerPixel = 388;
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsBytesPerLine = 392;
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsColorOrder = 396;
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsColorSpace = 400;
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderCupsNumColors = 420;
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const uint32 kHeaderPwgTotalPageCount = 452;
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kHeaderPwgCrossFeedTransform = 456;
440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst uint32 kHeaderPwgFeedTransform = 460;
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kPwgMaxPackedRows = 256;
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const int kPwgMaxPackedPixels = 128;
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstruct RGBA8 {
510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 red;
520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 green;
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 blue;
540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 alpha;
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch};
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstruct BGRA8 {
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 blue;
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 green;
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 red;
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint8 alpha;
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch};
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochtemplate <class InputStruct>
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochinline void encodePixelToRGB(const void* pixel, std::string* output) {
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const InputStruct* i = reinterpret_cast<const InputStruct*>(pixel);
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  output->push_back(static_cast<char>(i->red));
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  output->push_back(static_cast<char>(i->green));
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  output->push_back(static_cast<char>(i->blue));
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochtemplate <class InputStruct>
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochinline void encodePixelToMonochrome(const void* pixel, std::string* output) {
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const InputStruct* i = reinterpret_cast<const InputStruct*>(pixel);
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  output->push_back(static_cast<char>((i->red * kRedCoefficient +
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       i->green * kGreenCoefficient +
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       i->blue * kBlueCoefficient) /
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                      kColorCoefficientDenominator));
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}  // namespace
820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
830529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochPwgEncoder::PwgEncoder() {}
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void PwgEncoder::EncodeDocumentHeader(std::string* output) const {
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->clear();
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->append(kPwgKeyword, 4);
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid PwgEncoder::EncodePageHeader(const BitmapImage& image,
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  const PwgHeaderInfo& pwg_header_info,
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  std::string* output) const {
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  char header[kHeaderSize];
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memset(header, 0, kHeaderSize);
950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint32 num_colors =
970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      pwg_header_info.color_space == PwgHeaderInfo::SGRAY ? 1 : 3;
980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  uint32 bits_per_pixel = num_colors * kBitsPerColor;
990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderCupsDuplex,
1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.duplex ? 1 : 0);
1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderCupsHwResolutionHorizontal,
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.dpi);
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderCupsHwResolutionVertical,
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.dpi);
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderCupsTumble,
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.tumble ? 1 : 0);
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WriteBigEndian<uint32>(header + kHeaderCupsWidth, image.size().width());
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WriteBigEndian<uint32>(header + kHeaderCupsHeight,
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               image.size().height());
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WriteBigEndian<uint32>(header + kHeaderCupsBitsPerColor, kBitsPerColor);
1120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderCupsBitsPerPixel,
1130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               bits_per_pixel);
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WriteBigEndian<uint32>(header + kHeaderCupsBytesPerLine,
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               (bits_per_pixel * image.size().width() + 7) / 8);
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::WriteBigEndian<uint32>(header + kHeaderCupsColorOrder, kColorOrder);
1170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderCupsColorSpace,
1180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.color_space);
1190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderCupsNumColors, num_colors);
1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderPwgCrossFeedTransform,
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.flipx ? -1 : 1);
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderPwgFeedTransform,
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.flipy ? -1 : 1);
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::WriteBigEndian<uint32>(header + kHeaderPwgTotalPageCount,
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               pwg_header_info.total_pages);
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  output->append(header, kHeaderSize);
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochtemplate <typename InputStruct, class RandomAccessIterator>
1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid PwgEncoder::EncodeRow(RandomAccessIterator pos,
1310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                           RandomAccessIterator row_end,
1320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                           bool monochrome,
1330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                           std::string* output) const {
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // According to PWG-raster, a sequence of N identical pixels (up to 128)
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // can be encoded by a byte N-1, followed by the information on
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // that pixel. Any generic sequence of N pixels (up to 129) can be encoded
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // with (signed) byte 1-N, followed by the information on the N pixels.
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Notice that for sequences of 1 pixel there is no difference between
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // the two encodings.
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // We encode every largest sequence of identical pixels together because it
1420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // usually saves the most space. Every other pixel should be encoded in the
1430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // smallest number of generic sequences.
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // NOTE: the algorithm is not optimal especially in case of monochrome.
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  while (pos != row_end) {
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    RandomAccessIterator it = pos + 1;
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    RandomAccessIterator end = std::min(pos + kPwgMaxPackedPixels, row_end);
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Counts how many identical pixels (up to 128).
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    while (it != end && *pos == *it) {
1510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ++it;
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (it != pos + 1) {  // More than one pixel
154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      output->push_back(static_cast<char>((it - pos) - 1));
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (monochrome)
1560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        encodePixelToMonochrome<InputStruct>(&*pos, output);
1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      else
1580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        encodePixelToRGB<InputStruct>(&*pos, output);
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pos = it;
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else {
1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // Finds how many pixels there are each different from the previous one.
1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // IMPORTANT: even if sequences of different pixels can contain as many
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // as 129 pixels, we restrict to 128 because some decoders don't manage
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // it correctly. So iterating until it != end is correct.
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      while (it != end && *it != *(it - 1)) {
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        ++it;
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Optimization: ignores the last pixel of the sequence if it is followed
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // by an identical pixel, as it is more convenient for it to be the start
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // of a new sequence of identical pixels. Notice that we don't compare
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // to end, but row_end.
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (it != row_end && *it == *(it - 1)) {
1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        --it;
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      output->push_back(static_cast<char>(1 - (it - pos)));
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      while (pos != it) {
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (monochrome)
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          encodePixelToMonochrome<InputStruct>(&*pos, output);
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        else
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          encodePixelToRGB<InputStruct>(&*pos, output);
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        ++pos;
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)inline const uint8* PwgEncoder::GetRow(const BitmapImage& image,
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       int row,
1890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       bool flipy) const {
1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return image.GetPixel(
1910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      gfx::Point(0, flipy ? image.size().height() - 1 - row : row));
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Given a pointer to a struct Image, create a PWG of the image and
1950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// put the compressed image data in the string.  Returns true on success.
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// The content of the string is undefined on failure.
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool PwgEncoder::EncodePage(const BitmapImage& image,
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            const PwgHeaderInfo& pwg_header_info,
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            std::string* output) const {
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // pwg_header_info.color_space can only contain color spaces that are
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // supported, so no sanity check is needed.
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  switch (image.colorspace()) {
2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case BitmapImage::RGBA:
2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return EncodePageWithColorspace<RGBA8>(image, pwg_header_info, output);
2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case BitmapImage::BGRA:
2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return EncodePageWithColorspace<BGRA8>(image, pwg_header_info, output);
2080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    default:
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      LOG(ERROR) << "Unsupported colorspace.";
2110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return false;
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochtemplate <typename InputStruct>
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool PwgEncoder::EncodePageWithColorspace(const BitmapImage& image,
2170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                          const PwgHeaderInfo& pwg_header_info,
2180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                          std::string* output) const {
2190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool monochrome = pwg_header_info.color_space == PwgHeaderInfo::SGRAY;
2200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EncodePageHeader(image, pwg_header_info, output);
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Ensure no integer overflow.
2230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK(image.size().width() < INT_MAX / image.channels());
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int row_size = image.size().width() * image.channels();
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int row_number = 0;
2270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  while (row_number < image.size().height()) {
228e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const uint8* current_row =
2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        GetRow(image, row_number++, pwg_header_info.flipy);
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int num_identical_rows = 1;
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // We count how many times the current row is repeated.
232e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    while (num_identical_rows < kPwgMaxPackedRows &&
233e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch           row_number < image.size().height() &&
234e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch           !memcmp(current_row,
2350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   GetRow(image, row_number, pwg_header_info.flipy),
236e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   row_size)) {
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      num_identical_rows++;
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      row_number++;
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    output->push_back(static_cast<char>(num_identical_rows - 1));
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Both supported colorspaces have a 32-bit pixels information.
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Converts the list of uint8 to uint32 as every pixels contains 4 bytes
2440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // of information and comparison of elements is easier. The actual
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Management of the bytes of the pixel is done by pixel_encoder function
2460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // on the original array to avoid endian problems.
2470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const uint32* pos = reinterpret_cast<const uint32*>(current_row);
2480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const uint32* row_end = pos + image.size().width();
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!pwg_header_info.flipx) {
2500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      EncodeRow<InputStruct>(pos, row_end, monochrome, output);
2510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
2520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // We reverse the iterators.
2530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      EncodeRow<InputStruct>(std::reverse_iterator<const uint32*>(row_end),
2540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             std::reverse_iterator<const uint32*>(pos),
2550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             monochrome,
2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             output);
257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace cloud_print
263