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