Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2015 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #include "SkBitmapRegionCodec.h" | |
| 9 #include "SkCanvas.h" | |
| 10 #include "SkCodec.h" | |
| 11 #include "SkCodecPriv.h" | |
| 12 #include "SkCodecTools.h" | |
| 13 | |
| 14 SkBitmapRegionCodec::SkBitmapRegionCodec(SkCodec* codec) | |
| 15 : INHERITED(codec->getInfo().width(), codec->getInfo().height()) | |
| 16 , fCodec(codec) | |
| 17 {} | |
| 18 | |
| 19 /* | |
| 20 * Three differences from the Android version: | |
| 21 * Returns a skia bitmap instead of an Android bitmap. | |
| 22 * Android version attempts to reuse a recycled bitmap. | |
| 23 * Removed the options object and used parameters for color type and sample size. | |
| 24 */ | |
| 25 SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWid th, int inputHeight, | |
| 26 int sampleSize, SkColorType dstColorType) { | |
| 27 | |
| 28 // Fix the input sampleSize if necessary. | |
| 29 if (sampleSize < 1) { | |
| 30 sampleSize = 1; | |
| 31 } | |
| 32 | |
| 33 // The client may not necessarily request a region that is fully within | |
| 34 // the image. We may need to do some calculation to determine what part | |
| 35 // of the image to decode. | |
| 36 | |
| 37 // The left offset of the portion of the image we want, where zero | |
| 38 // indicates the left edge of the image. | |
| 39 int imageSubsetX; | |
| 40 | |
| 41 // The size of the output bitmap is determined by the size of the | |
| 42 // requested region, not by the size of the intersection of the region | |
| 43 // and the image dimensions. If inputX is negative, we will need to | |
| 44 // place decoded pixels into the output bitmap starting at a left offset. | |
| 45 // If this is non-zero, imageSubsetX must be zero. | |
| 46 int outX; | |
| 47 | |
| 48 // The width of the portion of the image that we will write to the output | |
| 49 // bitmap. If the region is not fully contained within the image, this | |
| 50 // will not be the same as inputWidth. | |
| 51 int imageSubsetWidth; | |
| 52 bool imageContainsEntireSubset = set_subset_region(inputX, inputWidth, this- >width(), | |
| 53 &imageSubsetX, &outX, &imageSubsetWidth); | |
| 54 | |
| 55 // The top offset of the portion of the image we want, where zero | |
| 56 // indicates the top edge of the image. | |
| 57 int imageSubsetY; | |
| 58 | |
| 59 // The size of the output bitmap is determined by the size of the | |
| 60 // requested region, not by the size of the intersection of the region | |
| 61 // and the image dimensions. If inputY is negative, we will need to | |
| 62 // place decoded pixels into the output bitmap starting at a top offset. | |
| 63 // If this is non-zero, imageSubsetY must be zero. | |
| 64 int outY; | |
| 65 | |
| 66 // The height of the portion of the image that we will write to the output | |
| 67 // bitmap. If the region is not fully contained within the image, this | |
| 68 // will not be the same as inputHeight. | |
| 69 int imageSubsetHeight; | |
| 70 imageContainsEntireSubset &= set_subset_region(inputY, inputHeight, this->he ight(), | |
| 71 &imageSubsetY, &outY, &imageSubsetHeight); | |
| 72 | |
| 73 if (imageSubsetWidth <= 0 || imageSubsetHeight <= 0) { | |
| 74 SkCodecPrintf("Error: Region must intersect part of the image.\n"); | |
| 75 return nullptr; | |
| 76 } | |
| 77 | |
| 78 // Ask the codec for a scaled subset | |
|
msarett
2015/10/12 18:42:36
Up until here, this implementation is the same as
scroggo
2015/10/12 19:18:09
Would it be possible to pull out a common function
msarett
2015/10/21 19:15:09
I think this is a little cleaner. Let me know wha
| |
| 79 SkIRect subset = SkIRect::MakeXYWH(imageSubsetX, imageSubsetY, imageSubsetWi dth, | |
| 80 imageSubsetHeight); | |
| 81 SkISize scaledDimensions; | |
| 82 SkIRect scaledSubset; | |
| 83 SkCodec::Options options; | |
| 84 options.fSubset = ⊂ | |
| 85 options.fScaledDimensions = &scaledDimensions; | |
| 86 options.fScaledSubset = &scaledSubset; | |
| 87 if (!fCodec->getScaledSubsetDimensions(get_scale_from_sample_size(sampleSize ), options)) { | |
| 88 SkCodecPrintf("Error: Could not scale.\n"); | |
| 89 return nullptr; | |
| 90 } | |
| 91 | |
| 92 // Create the image info for the decode | |
| 93 SkAlphaType dstAlphaType = fCodec->getInfo().alphaType(); | |
| 94 if (kUnpremul_SkAlphaType == dstAlphaType) { | |
| 95 dstAlphaType = kPremul_SkAlphaType; | |
| 96 } | |
| 97 SkImageInfo decodeInfo = SkImageInfo::Make(scaledSubset.width(), scaledSubse t.height(), | |
| 98 dstColorType, dstAlphaType); | |
| 99 | |
| 100 // Construct a color table for the decode if necessary | |
| 101 SkAutoTUnref<SkColorTable> colorTable(nullptr); | |
| 102 SkPMColor* colorPtr = nullptr; | |
| 103 int* colorCountPtr = nullptr; | |
| 104 int maxColors = 256; | |
| 105 SkPMColor colors[maxColors]; | |
| 106 if (kIndex_8_SkColorType == dstColorType) { | |
| 107 // TODO (msarett): This performs a copy that is unnecessary since | |
| 108 // we have not yet initialized the color table. | |
| 109 // And then we need to use a const cast to get | |
| 110 // a pointer to the color table that we can | |
| 111 // modify during the decode. Is there a better | |
| 112 // way to do this? Can we allocate memory to | |
| 113 // decode into and then create the bitmap after | |
| 114 // the decode? Can we create an SkColorTable | |
| 115 // without copying the colors? | |
| 116 colorTable.reset(new SkColorTable(colors, maxColors)); | |
| 117 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | |
| 118 colorCountPtr = &maxColors; | |
| 119 } | |
| 120 | |
| 121 // Initialize the destination bitmap | |
| 122 SkAutoTDelete<SkBitmap> bitmap(new SkBitmap()); | |
| 123 int scaledOutX = 0; | |
| 124 int scaledOutY = 0; | |
| 125 int scaledOutWidth = scaledSubset.width(); | |
| 126 int scaledOutHeight = scaledSubset.height(); | |
| 127 if (!imageContainsEntireSubset) { | |
| 128 scaledOutX = outX / sampleSize; | |
| 129 scaledOutY = outY / sampleSize; | |
| 130 int scaledExtraX = (inputWidth - outX - imageSubsetWidth) / sampleSize; | |
| 131 int scaledExtraY = (inputHeight - outY - imageSubsetHeight) / sampleSize ; | |
| 132 scaledOutWidth += scaledOutX + scaledExtraX; | |
| 133 scaledOutHeight += scaledOutY + scaledExtraY; | |
| 134 } | |
| 135 SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight); | |
| 136 if (!bitmap->tryAllocPixels(outInfo, nullptr, colorTable.get())) { | |
| 137 SkCodecPrintf("Error: Could not allocate pixels.\n"); | |
| 138 return nullptr; | |
| 139 } | |
| 140 | |
| 141 // Zero the bitmap if the region is not completely within the image. | |
| 142 // TODO (msarett): Can we make this faster by implementing it to only | |
| 143 // zero parts of the image that we won't overwrite with | |
| 144 // pixels? | |
| 145 // TODO (msarett): This could be skipped if memory is zero initialized. | |
| 146 // This would matter if this code is moved to Android and | |
| 147 // uses Android bitmaps. | |
| 148 if (!imageContainsEntireSubset && SkCodec::kNo_ZeroInitialized == options.fZ eroInitialized) { | |
| 149 bitmap->eraseColor(0); | |
| 150 } | |
| 151 | |
| 152 // Decode into the destination bitmap | |
| 153 void* dst = bitmap->getAddr(scaledOutX, scaledOutY); | |
| 154 size_t rowBytes = bitmap->rowBytes(); | |
| 155 SkCodec::Result result = fCodec->getPixels(decodeInfo, dst, rowBytes, &optio ns, colorPtr, | |
| 156 colorCountPtr); | |
| 157 if (SkCodec::kSuccess != result && SkCodec::kIncompleteInput != result) { | |
|
scroggo
2015/10/12 19:18:09
Why is incomplete considered fatal?
msarett
2015/10/21 19:15:09
Success and incomplete are both non-errors. Alter
| |
| 158 SkCodecPrintf("Error: Could not get pixels.\n"); | |
| 159 return nullptr; | |
| 160 } | |
| 161 | |
| 162 return bitmap.detach(); | |
| 163 } | |
| 164 | |
| 165 bool SkBitmapRegionCodec::conversionSupported(SkColorType colorType) { | |
| 166 // FIXME: Call virtual function when it lands. | |
| 167 SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fCodec->getInfo().alph aType(), | |
| 168 fCodec->getInfo().profileType()); | |
| 169 return conversion_possible(info, fCodec->getInfo()); | |
| 170 } | |
| OLD | NEW |